Lezione 11 – Corso di Elettronica Creativa con Arduino Sensor Kit

Accelerometro

L’accelerometro del Sensor Kit è un “sensore di movimento” a tre assi (X, Y, Z) capace di misurare come cambia la velocità di un oggetto nello spazio. Anche quando è fermo, l’accelerometro non rileva “zero accelerazione” in quanto misura la gravità terrestre, circa 1 g (≈ 9,81 m/s²). Questa caratteristica è utilissima perché ci permette sia di capire se e quanto ci stiamo muovendo, sia di stimare l’inclinazione del modulo rispetto alla verticale. In pratica: se appoggio la scheda piatta sul banco, il valore lungo Z sarà vicino a 1 g; se lo incliniamo, la gravità si “ridistribuisce” tra X e Y e possiamo ricavare l’angolo di inclinazione.

Con i dati che fornisce l’accelerometro possiamo fare molte cose: visualizzare scosse e vibrazioni (come un mini sismografo), creare un avviso di caduta, progettare giochi di equilibrio o semplicemente tracciare i movimenti sulla Serial Plotter. In questa lezione impareremo a leggere le tre componenti, a filtrare il rumore e a trasformare quei numeri in azioni concrete (LED, buzzer, messaggi su OLED).

Un briciolo di teoria

L’accelerometro misura accelerazioni lungo X, Y, Z e come dicevo sopra, da fermo “vede” la gravità (~1 g ≈ 9,81 m/s²).

Il modulo del vettore accelerazione è:

Con il dispositivo quasi fermo, possiamo stimare l’inclinazione rispetto alla verticale usando solo la gravità:

che rappresenta l’angolo rispetto all’asse Z (in gradi).

Caratteristiche tecniche (per i più esperti)

  • Tipo sensore: MEMS accelerometro triassiale digitale.
  • Interfacce: I²C e SPI digitali (il modulo Grove è normalmente usato in I²C sul Sensor Kit).
  • Indirizzo I²C: di default 0x19, commutabile a 0x18 (pin SA0/SDO a GND).
  • Campo di misura (full-scale): ±2 g, ±4 g, ±8 g, ±16 g (selezionabile via registro).
  • Risoluzione dati: uscita fino a 16-bit; modalità operative low-power/normal/high-resolution (fino a 12-bit effettivi).
  • Frequenza di campionamento (ODR): da 1 Hz fino a 5.3 kHz (a seconda della modalità).
  • Funzioni integrate:
    • 2 generatori di interrupt programmabili (motion, free-fall, wake-up).
    • Rilevamento orientamento 6D/4D, self-test, FIFO 32 campioni.
  • Alimentazione (chip): 1.71–3.6 V; consumo molto basso (fino a ~2 µA in ultra-low-power). Il modulo Grove è compatibile 3 V / 5 V.
  • Intervallo di temperatura operativa: −40 °C … +85 °C.

Informazioni utili per l’uso nell’Arduino Sensor Kit

  • Con la libreria Arduino_SensorKit.h leggete le tre componenti con Accelerometer.readX() / readY() / readZ(); i valori restituiti sono interpretati in g (gravità ≈ 1 g a riposo).
  • Il modulo Grove usato nel Sensor Kit documenta esplicitamente indirizzi I²C, range e compatibilità 3V/5V, utile se sorgono conflitti su bus I²C o serve cambiare indirizzo.

Collegamenti

Per quanto riguarda i collegamenti è sufficiente connettere il sensore ad uno degli ingressi I²C della Base Shield.

Esempio 01 – Lettura accelerometro 3 assi

/*
  Prof. Maffucci Michele
  02.10.2025
  Lettura accelerometro 3 assi – Arduino Sensor Kit
*/

#include <Arduino_SensorKit.h>   // Libreria unica per i moduli del Sensor Kit

const unsigned long intervalloMs = 500;  // intervallo tra una stampa e la successiva

void setup() {
  // Inizializzazione porta seriale per inviare i dati al PC
  Serial.begin(9600);

  // ATTENZIONE:
  // while(!Serial); serve ad ASPETTARE che il monitor seriale sia stato aperto
  // (utile sulle schede con USB nativa, esempio: Arduino UNO R4 WiFi, Leonardo, MKR).
  // Così non "perdi" le prime stampe.
  // Su schede senza USB nativa non è necessario e puoi rimuoverlo.
  while (!Serial) { ; }

  // Avvio dell'accelerometro a 3 assi
  Accelerometer.begin();
}

void loop() {
  // Lettura delle tre componenti di accelerazione (in g)
  float accelX = Accelerometer.readX();  // Asse X
  float accelY = Accelerometer.readY();  // Asse Y
  float accelZ = Accelerometer.readZ();  // Asse Z

  // Stampa in formato semplice: x:..  y:..  z:..
  Serial.print("x: "); 
  Serial.print(accelX, 3);   // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("y: "); 
  Serial.print(accelY, 3);
  Serial.print("  ");

  Serial.print("z: "); 
  Serial.println(accelZ, 3);

  delay(intervalloMs);
}

Esempio 02: Accelerometro – Stampa su Serial Monitor e display OLED

Visualizzazione delle componenti x, y e z dell’accelerazione su Serial Monitor e display OLED

/*
  Prof. Maffucci Michele
  02.10.2025
  Lettura accelerometro 3 assi – Arduino Sensor Kit
  Stampa su Serial Monitor e display Oled
*/

#include <Arduino_SensorKit.h>  // Libreria unica per i moduli del Sensor Kit

const unsigned long intervalloMs = 500;  // intervallo tra una stampa e la successiva

void setup() {
  // Inizializzazione porta seriale per inviare i dati al PC
  Serial.begin(9600);

  // ATTENZIONE:
  // while(!Serial); serve ad ASPETTARE che il monitor seriale sia stato aperto
  // (utile sulle schede con USB nativa, esempio: Arduino UNO R4 WiFi, Leonardo, MKR).
  // Così non "perdi" le prime stampe.
  // Su schede senza USB nativa non è necessario e puoi rimuoverlo.
  while (!Serial) { ; }

  // Avvio dell'accelerometro a 3 assi
  Accelerometer.begin();
  Oled.begin();
  // Inizializza il display OLED.
  // Fa partire la comunicazione I2C e manda al display la sequenza di avvio.
  // Senza questa riga lo schermo non mostra nulla.

  Oled.setFlipMode(true);
  // Ruota il contenuto di 180° (utile se lo vedi capovolto).
  // Se nel tuo caso appare già dritto, puoi mettere false: Oled.setFlipMode(false);

  Oled.setFont(u8x8_font_chroma48medium8_r);
  // Sceglie il font (carattere) 8x8.
  // Con un font 8x8 il display 128x64 si comporta come una griglia 16 colonne × 8 righe.
  // Significa che setCursor(colonna, riga) userà numeri tra 0..15 (colonne) e 0..7 (righe).

  Oled.clear();
  // Pulisce lo schermo (cancella tutto quello che c’era prima).
}

void loop() {
  // Lettura delle tre componenti di accelerazione (in g)
  float accelX = Accelerometer.readX();  // Asse X
  float accelY = Accelerometer.readY();  // Asse Y
  float accelZ = Accelerometer.readZ();  // Asse Z

  // Stampa in formato semplice: x:..  y:..  z:..
  Serial.print("x: ");      // stampa la stringa x: su Serial Monitor
  Serial.print(accelX, 3);  // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("y: ");      // stampa la stringa y: su Serial Monitor
  Serial.print(accelY, 3);  // 3 decimali per leggibilità
  Serial.print("  ");

  Serial.print("z: ");        // stampa la stringa z: su Serial Monitor
  Serial.println(accelZ, 3);  // 3 decimali per leggibilità

  Oled.setCursor(0, 0);           // colonna 0, riga 0
  Oled.println("ACCELERAZIONE");  // stampa la stringa e va a capo

  Oled.setCursor(0, 2);   // colonna 0, riga 2
  Oled.print("x: ");      // stampa la stringa x:
  Oled.print(accelX, 3);  // stampa la componente x dell'accelerazione con 3 cifre decimali

  Oled.setCursor(0, 3);   // colonna 0, riga 3
  Oled.print("y: ");      // stampa la stringa y:
  Oled.print(accelY, 3);  // stampa la componente y dell'accelerazione con 3 cifre decimali
  Oled.refreshDisplay();

  Oled.setCursor(0, 4);   // colonna 0, riga 4
  Oled.print("z: ");      // stampa la stringa z:
  Oled.print(accelZ, 3);  // stampa la componente z dell'accelerazione con 3 cifre decimali
  Oled.refreshDisplay();

  delay(intervalloMs);
}

Esempio 03: Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z)

Stampa i tre assi con etichette e tab in un’unica riga per campione, in questo modo l’IDE mostra tre curve (X, Y, Z).

/*
  Prof. Maffucci Michele
  02.10.2025
  Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z)

  Nota: una riga = un campione; valori etichettati e separati da TAB -> 3 curve nel Plotter.
*/

#include <Arduino_SensorKit.h&gt

const unsigned long periodoCampionamentoMs = 10;  // circa 100 Hz (riduci/aumenta a piacere)

void setup() {
  Serial.begin(115200);
  // Attende l'apertura del Monitor/Plotter Seriali sulle schede con USB nativa
  while (!Serial) { ; }

  Accelerometer.begin();

  // Messaggio di avvio (facoltativo)
  Serial.println("Traccio X,Y,Z (g) - dati GREZZI (nessun filtro)");
}

void loop() {
  // Letture grezze in g
  float x = Accelerometer.readX();
  float y = Accelerometer.readY();
  float z = Accelerometer.readZ();

  // Stampa “label:valore” separati da TAB → il Plotter disegna tre curve
  Serial.print("X:");
  Serial.print(x, 3);
  Serial.print('\t');
  Serial.print("Y:");
  Serial.print(y, 3);
  Serial.print('\t');
  Serial.print("Z:");
  Serial.println(z, 3);

  delay(periodoCampionamentoMs);
}

Versione per esperti

Esempio 04: Accelerometro – Uscita per Serial Plotter (3 curve: X, Y, Z) con filtro passa-basso

Come avete potuto notare nella versione precedente le curve delle tre componenti dell’accelerazione erano seghettate e venivano rappresentate anche piccoli tremolii.

Per evitare questo problema useremo nello sketch che segue un filtro IIR (passa-basso) che smusserà il rumore.

Quali sono i vantaggi nell’utilizzo di un filtro passa basso:

  • Rumore: piccole variazioni veloci e indesiderate nei dati (tremolio della mano, vibrazioni del banco, disturbi elettrici).
  • Passa-basso: un filtro che lascia passare i cambiamenti lenti (il “trend” reale del movimento) e attenua i cambiamenti veloci (dovuti al rumore).
  • IIR (Infinite Impulse Response): significa che l’uscita del filtro dipende sia dal valore attuale sia dall’uscita precedente. In pratica: il filtro “ricorda” un po’ del passato -> è una media mobile esponenziale.

Formule per ogni asse:

uscita_filtrata(t) = α * ingresso(t) + (1−α) * uscita_filtrata(t−1)

α è un numero tra 0 e 1:

  • α piccolo (es. 0.1) > molto liscio (tanto filtraggio) ma più lento a seguire i cambiamenti.
  • α grande (es. 0.6) > meno liscio (meno filtraggio) ma più reattivo.

In sintesi:
scegliere α in base al compromesso “più liscio vs più rapido”.

/*
  Prof. Maffucci Michele
  02.10.2025
  Accelerometro - Uscita per Serial Plotter (3 curve: X, Y, Z) con filtro IIS (passa-basso)

  Note:
  - Il Serial Plotter IDE riconosce coppie "etichetta:valore" sulla stessa riga,
    separate da TAB. Ogni riga = un campione nel tempo.
*/

#include <Arduino_SensorKit.h&gt

const unsigned long periodoCampionamentoMs = 10;  // circa 100 Hz
const bool usaFiltro = true;                      // metti false se vuoi i dati grezzi
const float alfa = 0.2;                           // 0..1 (più piccolo = più filtrato)

float xF = 0, yF = 0, zF = 0;  // stati del filtro

void setup() {
  Serial.begin(115200);

  // Serve ad attendere l'apertura del Monitor/Plotter Seriali sulle schede con USB nativa,
  // così non perdete le prime stampe (su UNO "classico" puoi toglierlo senza problemi).
  while (!Serial) { ; }

  Accelerometer.begin();

  // (Facoltativo) riga di "header" informale: non necessaria, ma utile a chi guarda il log
  Serial.println("Pronto: traccio X,Y,Z (g) su Serial Plotter");
}

void loop() {
  // Letture in g
  float x = Accelerometer.readX();
  float y = Accelerometer.readY();
  float z = Accelerometer.readZ();

  if (usaFiltro) {
    // Filtro IIR (passa-basso) molto semplice per smussare il rumore
    xF = alfa * x + (1.0f - alfa) * xF;
    yF = alfa * y + (1.0f - alfa) * yF;
    zF = alfa * z + (1.0f - alfa) * zF;

    // Stampa "label:valore" separati da TAB > tre curve nel Plotter
    Serial.print("X:");
    Serial.print(xF, 3);
    Serial.print('\t');
    Serial.print("Y:");
    Serial.print(yF, 3);
    Serial.print('\t');
    Serial.print("Z:");
    Serial.println(zF, 3);
  } else {
    Serial.print("X:");
    Serial.print(x, 3);
    Serial.print('\t');
    Serial.print("Y:");
    Serial.print(y, 3);
    Serial.print('\t');
    Serial.print("Z:");
    Serial.println(z, 3);
  }

  delay(periodoCampionamentoMs);
}

Analizziamo nel dettaglio la parte del filtro.

xF = alfa * x + (1.0f - alfa) * xF;
yF = alfa * y + (1.0f - alfa) * yF;
zF = alfa * z + (1.0f - alfa) * zF;

xF = alfa * x + (1.0f - alfa) * xF;

  • x è il dato grezzo appena letto dall’accelerometro sull’asse X.
  • xF è il dato filtrato (uscita del filtro) per l’asse X.
  • alfa * x prende una frazione del dato nuovo (quanto “peso” dai alla misura attuale).
  • (1.0f - alfa) * xF prende una frazione del valore filtrato precedente (la “memoria”).
  • La somma dei due termini fornisce un valore ammorbidito: meno sensibile ai picchi improvvisi.

Nota sul suffisso f: indica un float letterale (utile per evitare promozioni a double in alcune piattaforme).

yF = alfa * y + (1.0f - alfa) * yF;

  • Identico ragionamento, ma applicato all’asse Y: nuova misura y + memoria del filtrato yF.
  • Mantieni alfa uguale sugli assi per coerenza visiva nel Plotter.

zF = alfa * z + (1.0f - alfa) * zF;

  • Stessa cosa per l’asse Z: la componente verticale (spesso contiene circa 1 g).
  • Filtrare Z aiuta a vedere meglio oscillazioni lente e a ridurre tremolii.

Qualche nota pratica

  1. Inizializzazione: se impostate xF = yF = zF = 0 all’inizio, i primi campioni possono “salire” gradualmente verso il valore reale (breve transitorio). Se volete partire subito “allineati”, potete inizializzare xF=yF=zF al primo dato letto.
  2. Scelta di alfa:
    0.1-0.3 > grafico molto liscio (meno rumore), risposta più lenta.
    0.4-0.7 > più reattivo, ma un po’ più “seghettato”.

Buon Coding a tutti 🙂

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.