MEMS, dalla teoria alla pratica: usiamo un Accelerometro con Arduino

MEMS

Nella puntata precedente abbiamo parlato degli aspetti tecnologici inerenti la fabbricazione dei Micro-Electro Mechanical Systems. Come vi avevamo annunciato, però, questo non esaurisce il panorama degli argomenti da trattare, c'è molto di più! E per questo, oggi, vedremo di scoprire ancora meglio questo mondo così variegato. Faremo degli accenni alle nanotecnologie, autentica scommessa per il futuro, e poi trasformeremo le nozioni apprese in pratica e programmazione grazie all'impiego di un accelerometro e della popolarissima scheda Arduino. Siete pronti?

Come detto in apertura, questa è solo la seconda parte dell'intervento e così come detto la scorsa volta, lo scopo doveva essere quello di far vedere, applicati, in maniera pratica e concreta i concetti che la teoria ha permesso di trasformare in sistemi. Quello che vedremo, tra un attimo, è la prova, il test di un accelerometro che è stato configurato ed utilizzato con Arduino.
Prima di proseguire, però, vorrei fare un breve

accenno alle nanotecnologie

Questo argomento è certamente molto vasto ed è impossibile trattarlo in un unico articolo. Ci vorrebbe un corso dedicato. Però quello che è importante sottolineare è che esiste ed è concreta la possibilità di realizzare strutture sub-micrometriche che lavorino in diversi campi, secondo diversi principi e soprattutto inseguendo le caratteristiche più spinte che riusciamo ad immaginare.
La tecnologia del silicio in questi casi risulta quanto mai inefficace dal momento che le dimensioni sono troppo piccole perché si possa sempre pensare di utilizzare questo materiale; esistono processi più idonei, più precisi e con delle rese assolutamente più interessanti.
Esistono, altresì, materiali più performanti e più adatti a questo genere di esigenze ed applicazioni.
In questo panorama che si presenta sfaccettato e complesso si inseriscono perfettamente i nanotubi di carbonio. Ed è proprio di questo che abbiamo accennato a Firenze.
Esistono le cosìddette forme "allotropiche".
Di allotropi del carbonio sono conosciuti alcuni tipi: carbonio amorfo, grafite, diamanti e fullereni.
Quando parliamo della sua forma amorfa, ci riferiamo essenzialmente alla grafite nella quale rimane inalterata la struttura cristallina.
A pressione normale il carbonio prende forma di grafite; qui ogni atomo è legato ad altri tre come possiamo vedere più avanti.
A pressioni molto alte il carbonio forma un allotropo chiamato diamante. Qui ogni atomo è legato ad altri quattro. Tutti sappiamo che la forza del legame tra gli atomi all'interno di questa struttura rappresenta sostanzialmente il più solido dei legami possibili e conosciuti.
Pressione e temperatura, quindi, governano le transizioni tra una configurazione dell'altra, portando alla formazione di legami più o meno intensi e alla descrizione di geometrie e strutture cristalline sempre più complesse.

I tipi sono descritti nella seguente immagine:

dove:
a) diamante;
b) grafite;
c) lonsdaliete;
d) fullerene C60;
e) fullerene C540;
f) fullerene C70;
g) amorfo;
h) nanotubi.

I nanotubi sono particolari fullereni che dimostrano di avere un diametro estremamente piccolo ed un rapporto lunghezza/diametro pari a diversi ordini di grandezza. La struttura è qualitativamente simile alla grafite ma invece della configurazione esagonale sono globalmente pentagonale tranne all'inizio ed alla fine. Lì si hanno strutture a forma di cupola che riprendono la struttura del carbonio C60.
Lungi dall'essere state completamente analizzati, le proprietà dei fullereni restano ancora tutte da scoprire. Ciò nonostante, diversi esperimenti li indicano come collocati direttamente sui GATE dei MOSFET di nuova generazione. Tale idea non è l'unica a vederli impiegati perché le nanotecnologie, più in generale, strizzano l'occhio a diverse grandezze e possibilità tra cui il computer quantistico, le strutture quantum confined ed i dispositivi basati sull'effetto tunnel risonante.

Vediamone subito uno

Per provare ad essere più pratico possibile, eccovi un esempio di accelerometro.
L'LSM303 è un accelerometro tri-assiale tilt compensated:

  • Tensione di alimentazione (analogica): 2.5 V to 3.3 V
  • Tensione di alimentazione (digitale) IOs: 1.8 V
  • Power-down mode;
  • 3 canali per magnetic field e 3 canali per accelerazione;
  • fondo scala del campo magnetico (in Gauss): da ±1.3 a
  • ±8,1;
  • fondo scala selezionabile dinamicamente tra: ±2g, ±4g e
  • ±8g;
  • profondità di dato: 16-bit;
  • interfaccia I2C;
  • 2 generatori indipendenti e programmabili per rilevazione
  • free-fall e motion detection;
  • embedded self-test;
  • funzine sleep-to-wakeup (accelerometro);
  • rilevazione dell'orientazione 6D.

Il motivo per cui è stato scelto questo accelerometro è presto detto: si tratta di un componente che conosco perché ce l'ho disponibile, l'ho studiato e col quale ho lavorato. Inoltre si tratta di un dispositivo straordinariamente coerente con l'argomento di oggi. Inoltre ve ne parlo perché è dotato di un'interfaccia di comunicazione molto comoda, l'I2C.

L'altra volta parlavamo di campi applicativi quindi, entrando nello specifico, diciamo che il particolare modello di accelerometro che abbiamo indicato in precedenza, così come indica la documentazione ufficiale, è molto indicato per: "Compensated compassing", "Map rotation", "Position detection", "Motion-activated functions", "Free-fall detection", "Intelligent power-saving for handheld devices", "Display orientation", "Gaming and virtual reality input devices", "Impact recognition and logging", "Vibration monitoring and compensation".

Un caso pratico

Come abbiamo detto, specifiche e campi applicativi vanno di pari passo. Nel recente passato mi sono occupato delle applicazioni spaziali. Le specifiche che avevo sono riportate per intero in questo documento di Thales Alenia Aerospace.

Stiamo immaginando di utilizzare un accelerometro che sia anche magnetometro, giroscopio. E questo perché abbiamo bisogno di un sistema che sia in grado di darci il maggior numero di informazioni possibili e diventare il cuore pulsante di una Inertial Measurements Unit (IMU).
Bene, possiamo pensare che tra i campi applicativi di cui abbiamo parlato in precedenza ci sia una che conosciamo molto bene, ovvero la funzionalità di orientazione del display, che su tutti gli smartphone è ampiamente implementata.
Come si fa? Che cosa ci serve? Noi vogliamo fare in modo da leggere il valore in uscita dal sensore per rilevare che lo spostamento è avvenuto.
Uno spostamento qualsiasi? Ovviamente no! Perché se fosse uno spostamento qualsiasi, la prospettiva potrebbe non essere corretta e a quel punto nascerebbero altre domande, per esempio: "ha senso ruotare lo schermo di 90° quando l'osservatore non ha fatto una richiesta di questo spostamento?" Quindi supponiamo di fissare la soglia a 90°.
Per fare questo, ben poco delle caratteristiche del dispositivo sarà utile: per esempio ci servirà sicuramente la tensione operativa, il range full-scale nonché la precisione. Bene, andiamo a vedere che cosa ci dice il datasheet del componente.

Guardiamo il datasheet

Qualunque sia il componente, a prescindere dall'applicazione, in qualunque campo vi stiate muovendo, conoscere il dispositivo sarà la chiave verso il successo. Imparare a comprendere le caratteristiche del dispositivo è ovviamente, anche per questo, anche in questo caso, valgono tutte le considerazioni fatte in precedenza.
Particolare attenzione va posta rispetto alla precisione: quando diciamo che un dato viene rappresentato con un certo numero di cifre significative, specie all'uscita di un sensore che propone già un'uscita digitale, significa che quello è il numero teorico massimo di bit grazie ai quali il numero può essere rappresentato.
Questa indicazione, però, bisogna ricordarlo sempre, non è da prendere come verbo perché quella precisione ha sicuramente dei fattori limitanti, tra i quali le componenti di offset piuttosto che i rumori piuttosto che le vibrazioni casuali e quindi una serie di componenti che vanno a rendere meno significative specialmente le ultime cifre.
Ecco per quale motivo quello che abbiamo elencato in precedenza non è certamente tutto e solo quello che serve perché c'è molto di più.

Successivamente col dispositivo ci dobbiamo anche"parlare" e per farlo ci interessa molto sapere come dobbiamo comunicare, Quale interfaccia utilizzare, o quale delle interfacce disponibili è il caso di utilizzare, specie in funzione del resto del sistema. Ma anche il tipo di uscita, se analogica o digitale, e così via dicendo.
Dopodiché ancora non abbiamo finito perché serve sapere come si effettua il montaggio e per questo bisogna partire da quello che è riportato nella documentazione riguardo il package.
Onde evitare problematiche di qualunque tipo, bisogna tenere a mente che esistono anche altre specifiche.

La board

Ma adesso arriviamo al punto in cui questo intervento diventa pratico.
Vi faccio vedere che cosa serve per riuscire ad interfacciarsi con questo tipo di strumenti (prima) e per utilizzarli (poi) grazie anche a schede piuttosto semplici.
Per fare questa prova ho utilizzato Arduino, in maniera tale da fare tutto velocemente, anche e soprattutto per voi, per non appesantirvi.
Per comodità, l'accelerometro è stato già configurato all'interno di un sistema così fatto.

Avevo un'altra possibilità e cioè interfacciarmi direttamente con un accelerometro montato su una scheda della ST però magari questo ve lo faccio vedere la prossima volta.

Qui c'è poco da commentare se non che:

LSM303 ---------- Arduino
Vin                           3.3V
GND                         GND
SDA                           A4
SCL                            A5

Il display LCD è connesso tramite I2C (VCC = 5V).

Il codice

Tutti conoscete certamente l'IDE di Arduino e sapete anche come si creano le librerie.
Questa però deve essere una simulazione snella per cui più che creare una libreria ho fatto in modo da scrivere una breve documentazione del componente, ovviamente consultando attentamente il datasheet. Ho scritto soltanto quello che serve nell'immediato per cui non prendetela come una documentazione completa.
Se la cosa vi interessa, il listato è riportato qui e potete simularlo voi stessi.

#define SCALE 2 // valore full scale dell'accelerazione (valori possibili: 2, 4 o 8)
/* Definizione indirizzo LSM303 */
#define LSM303_MAG 0x1E // SA0 grounded
#define LSM303_ACC 0x18 // SA0 grounded
#define X 0
#define Y 1
#define Z 2
/* Variabili globali */
int accel[3]; // valori grezzi dell'accelerazione
int mag[3]; // valori grezzi del magnetometro
float realAccel[3]; // valori dell'accelerazione calcolati

/* Definizioni dei registri dell'LSM303 */
#define CTRL_REG1_A 0x20
#define CTRL_REG2_A 0x21
#define CTRL_REG3_A 0x22
#define CTRL_REG4_A 0x23
#define CTRL_REG5_A 0x24
#define HP_FILTER_RESET_A 0x25
#define REFERENCE_A 0x26
#define STATUS_REG_A 0x27
#define OUT_X_L_A 0x28
#define OUT_X_H_A 0x29
#define OUT_Y_L_A 0x2A
#define OUT_Y_H_A 0x2B
#define OUT_Z_L_A 0x2C
#define OUT_Z_H_A 0x2D
#define INT1_CFG_A 0x30
#define INT1_SOURCE_A 0x31
#define INT1_THS_A 0x32
#define INT1_DURATION_A 0x33
#define CRA_REG_M 0x00
#define CRB_REG_M 0x01
#define MR_REG_M 0x02
#define OUT_X_H_M 0x03
#define OUT_X_L_M 0x04
#define OUT_Y_H_M 0x05
#define OUT_Y_L_M 0x06
#define OUT_Z_H_M 0x07
#define OUT_Z_L_M 0x08
#define SR_REG_M 0x09
#define IRA_REG_M 0x0A
#define IRB_REG_M 0x0B
#define IRC_REG_M 0x0C

/* Definizione delle funzioni */
void initLSM303(int fs)
{
  LSM303_write(0x27, CTRL_REG1_A); // 0x27 =
  modalità normale, tutti gli assi attivi
    if ((fs==8)||(fs==4))
    LSM303_write((0x00 | (fs-fs/2-1)<<4),
    CTRL_REG4_A); // imposta full-scale
  else
    LSM303_write(0x00, CTRL_REG4_A);
  LSM303_write(0x14, CRA_REG_M); // 0x14 =
  output rate mag 30Hz
    LSM303_write(0x00, MR_REG_M); // 0x00 =
  continouous conversion mode
}

void printValues(int * magArray, int * accelArray)
{
  /* stampa dei valori "come sono" */
  Serial.print(accelArray[X], DEC);
  Serial.print("\t");
  Serial.print(accelArray[Y], DEC);
  Serial.print("\t");
  Serial.print(accelArray[Z], DEC);
  Serial.print("\t\t");
  Serial.print(magArray[X], DEC);
  Serial.print("\t");
  Serial.print(magArray[Y], DEC);
  Serial.print("\t");
  Serial.print(magArray[Z], DEC);
  Serial.println();
  delay(1000);
}

float getHeading(int * magValue) {
  // paragrafo 1.2 dell'Application Note AN3192
  // pitch e roll = 0 => level position
  float heading = 180*atan2(magValue[Y], magValue[X])/PI;
  if (heading <0)
    heading += 360;
  return heading;
}

float getTiltHeading(int * magValue, float * accelValue) {
  // Appendice A dell'Application Note AN3192
  float pitch = asin(-accelValue[X]);
  float roll = asin(accelValue[Y]/cos(pitch));
  float xh = magValue[X] * cos(pitch) + magValue[Z] * sin(pitch);
  float yh = magValue[X] * sin(roll) * sin(pitch) + magValue[Y] * cos(roll) -
    magValue[Z] * sin(roll) * cos(pitch);
  float zh = -magValue[X] * cos(roll) * sin(pitch) + magValue[Y] * sin(roll)
    + magValue[Z] * cos(roll) * cos(pitch);
  float heading = 180 * atan2(yh, xh)/PI;
  if (yh >= 0)
    return heading;
  else
    return (360 + heading);
}

void getLSM303_accel(int * rawValues)
{
  rawValues[Z] = ((int)LSM303_read(OUT_X_L_A) << 8) | (LSM303_read(OUT_X_H_A));
  rawValues[X] = ((int)LSM303_read(OUT_Y_L_A) << 8) | (LSM303_read(OUT_Y_H_A));
  rawValues[Y] = ((int)LSM303_read(OUT_Z_L_A) << 8) | (LSM303_read(OUT_Z_H_A));
  // assegnamento corretto in funzione degli assi
}
void getLSM303_mag(int * rawValues)
{
  Wire.beginTransmission(LSM303_MAG);
  Wire.write(OUT_X_H_M);
  Wire.endTransmission();
  Wire.requestFrom(LSM303_MAG, 6);
  for (int i=0; i<3; i++)
    rawValues[i] = (Wire.read() << 8) | Wire.read();
}

// Lettura del sensore
byte LSM303_read(byte address)
{
  byte appo; // questa è solo una variabile di appoggio
  if (address >= 0x20)
    Wire.beginTransmission(LSM303_ACC);
  else
    Wire.beginTransmission(LSM303_MAG);
  Wire.write(address);
  if (address >= 0x20)
    Wire.requestFrom(LSM303_ACC, 1);
  else
    Wire.requestFrom(LSM303_MAG, 1);
  while(!Wire.available());
  appo = Wire.read();
  Wire.endTransmission();
  return appo;
}

// Scrittura dei dati
void LSM303_write(byte data, byte address)
{
  if (address >= 0x20)
    Wire.beginTransmission(LSM303_ACC);
  else
    Wire.beginTransmission(LSM303_MAG);
  Wire.write(address);
  Wire.write(data);
  Wire.endTransmission();
}

void setup() {
  Serial.begin(9600);
  Wire.begin();
  lcd.begin(20,4);
  lcd.setBacklight(HIGH);
  initLSM303(SCALE);
}

void loop() {
  getLSM303_accel(accel);
  while(!(LSM303_read(SR_REG_M) & 0x01));
  getLSM303_mag(mag); // prelevo i valori e li salvo nell'array mag
  for (int i=0; i<3; i++) {
    realAccel[i] = accel[i] / pow(2, 15) * SCALE; // calcolo i valori reali, in unità [g]
  }
  /* Stampa del level e dell'heading tilt-compensated */
  Serial.print("Heading: ");
  Serial.println(getHeading(mag), 3); // funzione solo se il sensore è a livello
  Serial.print("Heading_compensated: ");
  Serial.println(getTiltHeading(mag, realAccel), 3); // effetto della compensazione
  // e poi faccio le stesse cose sull'LCD, visto che la seriale serviva solo di debug
  lcd.print("Heading: ");
  lcd.print(getHeading(mag), 3);
  lcd.setCursor(0,1);
  lcd.print("Heading_cmp: ");
  lcd.print(getTiltHeading(mag, realAccel), 3);
  delay(500);
  lcd.clear();
}

Il codice funziona in maniera tale da implementare soltanto poche funzioni, come dicevo, quelle che servono.

Test

E per il ciclo "un'immagine vale più di mille parole":

Chiusura

Bene, con questo abbiamo concluso.
Quello che c'è da capire e da sapere sui MEMS certamente non potevo presentarvelo per intero però spero di avervi dato un'idea: l'elettronica analogica e la programmazione rappresentano un tutt'uno abbastanza completo e solidale.
Esistono una serie di dispositivi che possono essere utilizzati per applicazioni tra le più disparate. Dalla robotica fino alla domotica, dalle applicazioni biomedicali fino alla dosimetria, dalle applicazioni consumer fino all'avionica.
Tutto dipende, ovviamente, dal vostro budget e da che cosa volete fare, purtroppo esattamente in quest'ordine.

 

Riferimenti:
MEMS
MEMS Book
MEMX
MPCollab
Appunti e dispense del corso di Sistemi Micro e Nano Elettronici della prof.ssa Caterina Ciminelli (Politecnico di Bari)
Fonti consultate il: 10/05/2013

 

Quello che hai appena letto è un Articolo Premium reso disponibile affinché potessi valutare la qualità dei nostri contenuti!

 

Gli Articoli Tecnici Premium sono infatti riservati agli abbonati e vengono raccolti mensilmente nella nostra rivista digitale EOS-Book in PDF, ePub e mobi.
volantino eos-book1
Vorresti accedere a tutti gli altri Articoli Premium e fare il download degli EOS-Book? Allora valuta la possibilità di sottoscrivere un abbonamento a partire da € 2,95!
Scopri di più

2 Comments

  1. Luca Di Capita 12 novembre 2013
  2. Piero Boccadoro Piero Boccadoro 13 novembre 2013

Leave a Reply

Raspberry Pi 3 GRATIS! (Win10 compatibile)

Fai un abbonamento Platinum (EOS-Book + Firmware), ricevi in OMAGGIO la RASPBERRY 3, inviaci il tuo progetto e OTTIENI IL RIMBORSO