Problema Lettura Accelerometro

Buonasera,

io possiedo un robot della Pololu classe Zumo Shield v 1.2,

tra le altre caratteristiche, esso possiede un accelerometro/magnetometro a 3 assi LSM303D.

Io lo controllo tramite l'arduino 1 e nello specifico con la libreria LSM303.

I valori che l'accelerometro mostra sul seriale devono essere modificati
con un bitshift di 4 (>>4) e diviso per 1000 per ottenere l'accelerazione
in g (moltiplicabile poi per 9.81 per ottenere l'accelerazione in m/(s*s)).

Da fermo per esempio registra sull asse Z tra i 16000 e i 17000 che più o meno corrisponde
a un g (quindi funziona dato che la gravità la registra correttamente) e valori
molto più bassi sull asse X e Y (probabilmente dovuti al fatto che il piano non è
veramente piano ma leggermente inclinato e quei valori sono le componenti della gravità.

Tuttavia il fatto che senta la gravità a me interessa ben poco, io vorrei utilizzarlo in movimento e, se fatto muovere compaiono dei problemi. Io assumo che il robot possa muoversi solo in linea retta rispetto a sè stesso e che quindi durante il moto i valori d'accelerazione dovrebbero cambiare solo su un asse X o Y a seconda di come è posizionato sulla scheda, e invece no; in movimento i valori dell'accelerazione misurati variano sia sull'asse X che sull'asse Y.

Com'è possibile?

Essendo il tuo primo post Ti invitiamo a presentarti QUI
(dicci quali conoscenze hai di elettronica e di programmazione) e a leggere il regolamento QUI
se non lo hai già fatto.

Comunque benvenuto sul forum.

Attilio

ReCecco:
in movimento i valori dell'accelerazione misurati variano sia sull'asse X che sull'asse Y.
Com'è possibile?

Non sono un esperto, la butto li. Vibrazioni, ovvero il sensore è messo dove sente anche gli "scossoni" della scocca ?

Questa è la foto della posizione dell'unità inerziale

#include <Wire.h>  //nuovi
#include <L3G.h>
#include <math.h>
#include <EEPROM.h>
#include <LSM303.h>
#include <Pushbutton.h>

#define LM_dir_pin 8          //pin dei motori
#define LM_pwr_pin 10         //1 motore = 1 pin direzione(0/1), 1 pin potenza (0-256)
#define RM_dir_pin 7          //
#define RM_pwr_pin 9          //
#define PGRECO 3.14159          //3.14159 26535 89793 23846 26433 83279 50288
#define massa 0.350              //in kg
#define gravita 9.81


int defsp = 80;                //velocità standard
int defrotsp = 50;             //velocità di rotazione standard
int generic[4];                //generica (non dichiarare altro, se la usi una volta usa questa)

int movetime;
int tottime;

bool motor_dir;
float ax0;     //errore sistematico da piano inclinato (gravita)
float ay0;     //
float az0;     //
float ax=0;
float ay=0;
float az=0;

Pushbutton button(ZUMO_BUTTON);
LSM303 lsm;
//########## MOVIMENTO #############################################################################################################################################################
    //setta i motori ad una certa velocita, anche diversa fra di loro
    //uso: avanti()         entrambi a velocita std (defsp)
    //     avanti(vel) entrambi alla stessa vel
    //     avanti(vel,vel2) velocità diverse: avanza e gira contemporaneamente
void avanti(int left=-1,int right=-1){
    bool ldir=1;   //1=avanti 0=indietro
    bool rdir=1;
        //riporta entro valori massimi
    if(left>255)
        left=255;
    if(left<-255)
        left=-255;
    if(right>255)
        right=255;
    if(right<-255)
        right=-255;
        //imposta direzione (inverti se negativo)
    if(left<-1)
        digitalWrite(LM_dir_pin,1);
    else
        digitalWrite(LM_dir_pin,0);
    if(right<-1)
        digitalWrite(RM_dir_pin,1);
    else
        digitalWrite(RM_dir_pin,0);
        //nessun argomento
        //=avanti(defsp);
    if(left==-1){
        analogWrite(LM_pwr_pin,defsp);
        analogWrite(RM_pwr_pin,defsp);
        return;
    }
        //1 argomento
        //=avanti(velocità)  
    if(right==-1){
        analogWrite(LM_pwr_pin,left);
        analogWrite(RM_pwr_pin,left);
        return;
    }
        //2 argomenti, velocità diverse sui due motori, avanza girando
        //=avanti(vel1,vel2);
    analogWrite(LM_pwr_pin,left);
    analogWrite(RM_pwr_pin,right);
    return;
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //come avanti, ma inverte i valori
void indietro(int left=-1,int right=-1){
    if(right!=-1){
        avanti(-left,-right);
        return;
    }
    if(left!=-1){
        avanti(-left);
        return;
    }
    avanti(-defsp);
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //ferma i motori
void fermo(){
    avanti(0,0);
}
    //una funzione dall'indubbio utilizzo ;P
void accelera(){
    avanti(defsp+100);
}

//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //gira sul posto (direzione standard destra)
void ruota(int rotsp=defrotsp, char dir='d'){     //gira il robot in un verso o in un altro
    if(dir=='d'){                        //rotsp: rotation speed, valore analogico che va da 0 a 255; dir: direzione,d=destra altro=sinistra
        avanti(rotsp,-rotsp);
    }
    else{ 
        avanti(-rotsp,rotsp);
    }    
}

//########### MOVECAL ##############################################################################################################################################################
    //legge e converte i dati "grezzi" letti dall accellerometro in m/s"
float acc(char asse){
    int gen;
    float var;
    switch(asse){
        case 'x': {var=lsm.a.x>>4;break;}
        case 'y': {var=lsm.a.y>>4;break;}
        case 'z': {var=lsm.a.z>>4;break;}
        default: {var=lsm.a.x>>4;break;}
    }
    var/=1000;
    var*=gravita;
        //compensazione errori
    switch(asse){
        case 'x': {var-=ax0;break;}
        case 'y': {var-=ay0;break;}
        case 'z': {var-=az0;break;}
        default: {var-=ax0;break;}
    }
    return var;
}
//########### SET_STD_ACCELLERATION ##############################################################################################################################################################

void set_std_acceleration_values(int repeat){
    for(int i=0;i<repeat;i++){
        lsm.read();
        ax0+=lsm.a.x>>4;
        ay0+=lsm.a.y>>4;
        az0+=lsm.a.z>>4;
        delay(100);
    }
    ax0/=(float)repeat*1000;
    ax0*=gravita;
    ay0/=(float)repeat*1000;
    ay0*=gravita;
    az0/=(float)repeat*1000;
    az0*=gravita;
}

//############  SETUP  #############################################################################################################################################################

void setup() {
    Serial.begin(9600);
    Serial.print("\nstarting setup..");
    Wire.begin();
    lsm.init();
    lsm.enableDefault();
    set_std_acceleration_values(10);
    Serial.print("\nax0: ");Serial.print(ax0);Serial.print("  ay0: ");Serial.print(ay0);Serial.print("  az0: ");Serial.println(az0);
    Serial.print("\nSetup ok");
    button.waitForButton();
    Serial.print("\npressed");
    delay(1000);
}

void loop(){
    tottime=millis();
    avanti(100);
    while((millis()-tottime)<2000){
        movetime=millis();
        delay(100);
        lsm.read();
        ax=acc('x');
        ay=acc('y');
        az=acc('z');
        Serial.print("ax = ");Serial.print(ax);Serial.print("\t");Serial.print("ay = ");Serial.print(ay);Serial.print("\t");Serial.print("az = ");Serial.print(az);Serial.println("\t");
    }
    fermo();
    while(1){}
    delay(250);
}

Questo è lo sketch con cui leggo le accelerazioni durante il movimento che dura 2 secondi.

in pratica ogni 100 millisecondi l'accelerometro legge la sua accelerazione sui 3 assi e la
mostra sul monitor. i primi 3 valori (ax0 ay0 e az0) sono i valori della gravità registrati da
fermo e quindi vengono sottratti a ogni misura successiva.

Di seguito riporto alcuni dati:

ax ay az
-0.15 0.14 -1.30
0.01 0.19 -1.03
0.06 0.27 -0.42
-0.56 0.19 0.11
0.18 0.34 -0.14
0.17 0.02 -0.01
-0.09 -0.32 -0.21

Secondo voi questi valori sono corretti per un accelerometro? (è la prima volta che ne uso
uno)

Se non filtri quei valori ti sfido a capirci qualcosa, come ti ha detto nid le vibrazioni influiscono molto, ma statisticamente tendono a 0 se integrate su lungo periodo.

Cosa intendi per filtrare?

ReCecco:
Cosa intendi per filtrare?

Il filtro piu semplice in assoluto è la media a finestra mobile, uno dei piu usati invece è il filtro di Kalman.

e in seguito al filtraggio cosa ottengo?

scusa per le domande probabilmente banali, ma essendo alla prima esperienza
non ho mai utilizzato questi filtri.

Considera che l'obiettivo finale dovrebbe essere misurare lo spazio percorso partendo
da queste accelerazioni

Obiettivo audace, integrando le misure due volte la misura finale essa diventa molto inaffidabile. Un po' di teoria delle misurazioni, tutte le misurazione hanno un certo livello di incertezza, il grado di non conoscenza del misurato(molto a spanne, senza tirare in ballo lo scarto medio quadratico, la tolleranza) partiamo da questo per dire che la misura che fai non è perfetta, fare la media tra piu misure riduce l'incertezza, in caso di stazionarietà non è un problema, per esempio faccio un centinaio di misure e ne faccio la media, il risultato sarà molto piu affidabile della singola misura, questo però richiede tempo. In regime non stazionario la misura varia nel tempo e dobbiamo impiegare sistemi piu avanzati per la stima della misura, possiamo si fare ancora la media ma non potremo fare un arbitrario numero di misurazioni senza perdere informazione. Pertanto bisogna trovare sistemi piu avanzati, vedi il filtro di Kalman.

In altre parole con questo filtro otterrei una misura dell'accelerazione più affidabile?

Però il calcolo dello spazio mediante somma di istanti resterebbe?

E se sì la propagazione dell'errore in tante somme sarebbe influente sullo spazio finale calcolato?