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.
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.
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.
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.