MPU6050 Arduino: accelerometro, giroscopio e inclinazione
MPU6050 con Arduino: collegamento, indirizzo I2C, valori grezzi, calibrazione, inclinazione con atan2 e filtro complementare; libreria Adafruit, ESP32 e Pico.
L'MPU6050 unisce in un unico, minuscolo chip un accelerometro a 3 assi e un giroscopio a 3 assi ed è il sensore di movimento più usato nei progetti Arduino. Misura quanto è inclinata la scheda, in che direzione e a che velocità ruota, e se viene scossa o sta cadendo. Con questo sensore si costruiscono robot autobilanciati, droni, stabilizzatori per fotocamere (gimbal), contapassi e giochi controllati con il movimento. L'MPU6050 si collega ad Arduino con soli quattro fili, tramite I2C.
In questo articolo imparerai passo dopo passo come funziona l'MPU6050, i suoi assi e i valori grezzi, il collegamento I2C, la lettura con e senza libreria, la calibrazione, il calcolo dell'angolo di inclinazione con atan2 e il filtro complementare, che unisce i punti di forza dei due sensori. Poi costruiremo con un ESP32 un allarme che rileva le cadute e scriveremo il codice MicroPython per il Raspberry Pi Pico.

Cos'è l'MPU6050 e come funziona?
L'MPU6050, prodotto da InvenSense (oggi TDK), è una IMU, cioè un'unità di misura inerziale. Al suo interno ci sono minuscole strutture meccaniche in silicio (MEMS). L'accelerometro misura quanto si sposta una piccola massa sospesa su molle quando c'è un'accelerazione; poiché percepisce la gravità anche da fermo, un sensore appoggiato in piano sul tavolo indica circa 1 g (9,81 m/s²) sull'asse Z, e così puoi ricavare la sua inclinazione rispetto al suolo. Il giroscopio misura la velocità angolare, cioè di quanti gradi al secondo sta ruotando il sensore, sfruttando la forza di Coriolis che agisce su strutture vibranti. Le misure vengono convertite in numeri da ADC a 16 bit dentro il chip e lette tramite I2C. Il chip contiene anche un sensore di temperatura e un processore digitale di movimento (DMP) che può occuparsi dei calcoli di orientamento.
| Caratteristica | Valore |
|---|---|
| Sensori | Accelerometro a 3 assi + giroscopio a 3 assi + temperatura |
| Fondo scala accelerometro | ±2, ±4, ±8, ±16 g |
| Fondo scala giroscopio | ±250, ±500, ±1000, ±2000 °/s |
| Risoluzione | 16 bit (da -32768 a 32767 per asse) |
| Comunicazione | I2C, fino a 400 kHz |
| Indirizzo I2C | 0x68 (AD0 a GND) o 0x69 (AD0 a 3,3 V) |
| Tensione del chip | 2,375–3,46 V (la scheda GY-521 accetta 3,3–5 V) |
| Consumo | Circa 3,9 mA (5 µA in sleep) |
| Extra | DMP, FIFO da 1024 byte, interrupt di movimento, I2C ausiliario per un sensore esterno |
Assi, valori grezzi e sensibilità
Le frecce sulla scheda indicano gli assi X e Y; l'asse Z è perpendicolare alla scheda e punta verso l'alto. Il sensore fornisce per ogni asse un numero a 16 bit con segno. Per convertire questo valore grezzo in un'unità fisica lo dividi per la sensibilità del fondo scala scelto. Per esempio, nel fondo scala predefinito di ±2 g un valore grezzo di 16384 equivale a 1 g; con il sensore fermo sul tavolo leggerai az ≈ 16384 e ax, ay ≈ 0. Nel giroscopio, con fondo scala ±250 °/s, un valore di 131 corrisponde a una rotazione di 1 grado al secondo. Un fondo scala più ampio misura movimenti più bruschi ma mostra i piccoli cambiamenti in modo più grossolano, quindi scegli il più stretto che basta al tuo progetto.
| Impostazione | Fondo scala accelerometro | LSB/g | Fondo scala giroscopio | LSB/(°/s) |
|---|---|---|---|---|
| 0 | ±2 g | 16384 | ±250 °/s | 131 |
| 1 | ±4 g | 8192 | ±500 °/s | 65,5 |
| 2 | ±8 g | 4096 | ±1000 °/s | 32,8 |
| 3 | ±16 g | 2048 | ±2000 °/s | 16,4 |
Il chip misura anche la temperatura: °C = valore grezzo / 340 + 36,53. Questo valore indica più la temperatura del chip stesso che quella ambiente, ma poiché lo zero del giroscopio varia con la temperatura, è utile per le correzioni avanzate.
Collegamento dell'MPU6050: Arduino Uno, ESP32 e Pico
| Pin MPU6050 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT) |
| GND | GND | GND | GND |
| SCL | A5 | GPIO 22 | GP5 |
| SDA | A4 | GPIO 21 | GP4 |
| AD0 | Libero (indirizzo 0x68) | Libero (indirizzo 0x68) | Libero (indirizzo 0x68) |
| INT | D2 (facoltativo) | Qualsiasi GPIO (facoltativo) | Qualsiasi pin GP (facoltativo) |
| XDA, XCL | Non collegati | Non collegati | Non collegati |
Poiché la scheda GY-521 ha un regolatore a 3,3 V, puoi collegare VCC al pin 5V dell'Uno. Il pin AD0 è portato a GND sulla scheda da una resistenza da 4,7 kΩ, quindi lasciandolo libero l'indirizzo è 0x68; se vuoi usare due MPU6050 sullo stesso bus, collega a 3,3 V l'AD0 di uno dei due per portarne l'indirizzo a 0x69. Il pin INT segnala quando ci sono nuovi dati o quando viene rilevato un movimento; nei progetti semplici non serve collegarlo. Dopo il cablaggio è una buona abitudine verificare con uno scanner I2C che il sensore venga trovato; vedi come fare in Display LCD I2C.
Avvio rapido con una libreria: Adafruit MPU6050
- Apri il Gestore librerie nell'Arduino IDE e cerca Adafruit MPU6050.
- Quando durante l'installazione ti chiede delle dipendenze, scegli Install all: così vengono installate anche Adafruit Unified Sensor e Adafruit BusIO.
- Collega il sensore come nella tabella, carica lo sketch qui sotto e apri il Monitor seriale a 115200 baud.
- Apri il Plotter seriale dal menu Strumenti per seguire i sei assi in grafici dal vivo; inclinando la scheda cambiano le curve dell'accelerazione, ruotandola quelle del giroscopio.
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6
7void setup() {
8 Serial.begin(115200);
9 if (!mpu.begin()) { // varsayılan adres 0x68 / default address 0x68
10 Serial.println("MPU6050 bulunamadi / not found");
11 while (true) delay(10);
12 }
13 mpu.setAccelerometerRange(MPU6050_RANGE_4_G); // ±4 g
14 mpu.setGyroRange(MPU6050_RANGE_500_DEG); // ±500 °/s
15 mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); // titreşimi süz / filter out vibration
16}
17
18void loop() {
19 sensors_event_t a, g, t;
20 mpu.getEvent(&a, &g, &t);
21 Serial.print("ax:"); Serial.print(a.acceleration.x); // m/s²
22 Serial.print(" ay:"); Serial.print(a.acceleration.y);
23 Serial.print(" az:"); Serial.print(a.acceleration.z);
24 Serial.print(" gx:"); Serial.print(g.gyro.x); // rad/s
25 Serial.print(" gy:"); Serial.print(g.gyro.y);
26 Serial.print(" gz:"); Serial.print(g.gyro.z);
27 Serial.print(" T:"); Serial.println(t.temperature); // °C
28 delay(100);
29}La libreria Adafruit fornisce i risultati direttamente in unità fisiche: accelerazione in m/s², velocità angolare in rad/s e temperatura in °C. Per convertire un valore del giroscopio in gradi al secondo basta moltiplicarlo per 57,3. Il filtro passa-basso interno scelto con setFilterBandwidth riduce il rumore delle vibrazioni: 21 Hz è un buon punto di partenza per i movimenti della mano, mentre per cogliere urti brevi scegli 94 o 260 Hz. All'avvio la libreria legge il registro di identità del chip (WHO_AM_I) e begin() restituisce false se non vale 0x68.
Lettura senza libreria, calibrazione e angolo di inclinazione
Le librerie semplificano il lavoro, ma leggere direttamente i registri è molto istruttivo per capire cosa succede dentro il sensore. All'accensione l'MPU6050 è in modalità sleep: prima devi svegliarlo scrivendo 0 nel registro 0x6B (PWR_MGMT_1). Poi leggi 14 byte a partire dall'indirizzo 0x3B: 6 byte di accelerazione, 2 di temperatura e 6 di giroscopio. Ogni valore occupa due byte, prima quello più significativo. Ecco i registri principali usati nel codice e utili da conoscere:
| Registro | Indirizzo | Funzione |
|---|---|---|
| SMPLRT_DIV | 0x19 | Divisore della frequenza di campionamento |
| CONFIG | 0x1A | Filtro passa-basso interno (DLPF) |
| GYRO_CONFIG | 0x1B | Fondo scala del giroscopio (±250 … ±2000 °/s) |
| ACCEL_CONFIG | 0x1C | Fondo scala dell'accelerometro (±2 … ±16 g) |
| ACCEL_XOUT_H | 0x3B | Indirizzo da cui partono le misure (14 byte) |
| PWR_MGMT_1 | 0x6B | Sleep e sorgente di clock; scrivendo 0 si sveglia |
| WHO_AM_I | 0x75 | Identità; un MPU6050 originale restituisce 0x68 |
Con il sensore fermo, l'unica forza che l'accelerometro vede è la gravità. Osservando come si distribuisce sugli assi ricavi due angoli: il rollio attorno all'asse X, roll = atan2(ay, az), e il beccheggio attorno all'asse Y, pitch = atan2(−ax, √(ay² + az²)). A differenza dell'arcotangente normale, atan2 dà il segno giusto in tutti e quattro i quadranti e non divide per zero quando az si avvicina a zero. Per esempio, se leggi ay = 8192 e az = 14189, roll = atan2(8192, 14189) ≈ 30°. La rotazione attorno all'asse Z (imbardata, o yaw) invece l'accelerometro non la vede, perché non cambia il modo in cui la gravità si distribuisce sugli assi.
Entrambi i sensori hanno un punto debole. L'accelerometro è preciso nel lungo periodo ma molto rumoroso durante movimenti e vibrazioni, perché oltre alla gravità misura anche l'accelerazione del movimento stesso. Il giroscopio è fluido nel breve periodo, ma per ottenere un angolo sommi la velocità angolare nel tempo (angolo += velocità × dt), e anche un piccolo scostamento si accumula e fa derivare lentamente l'angolo. Il filtro complementare unisce i due: angolo = 0,98 × (angolo + giroscopio × dt) + 0,02 × angolo dell'accelerometro. Nel breve periodo si fida del giroscopio, nel lungo dell'accelerometro. A 100 Hz (dt = 0,01 s) questi coefficienti danno una costante di tempo di circa mezzo secondo: τ = 0,98 × 0,01 / 0,02 = 0,49 s.
La calibrazione è importante almeno quanto il filtro. Anche un giroscopio perfettamente fermo può mostrare uno scostamento costante (offset) di qualche °/s; se non lo correggi, l'angolo calcolato deriva di decine di gradi in pochi secondi. Lo sketch qui sotto, all'avvio e con il sensore fermo, fa la media di 500 letture e la sottrae da ogni lettura successiva. Durante la calibrazione appoggia la scheda su una superficie piana e non toccarla; poi osserva le curve di roll, pitch e yaw nel Plotter seriale.
1#include <Wire.h>
2
3const int MPU_ADDR = 0x68; // AD0 GND'de ya da boşta / AD0 to GND or floating
4const float GYRO_LSB = 131.0; // ±250 °/s aralığında 1 °/s / 1 °/s at the ±250 °/s range
5const float ALPHA = 0.98; // tamamlayıcı filtre katsayısı / complementary filter weight
6
7int16_t ax, ay, az, tempRaw, gx, gy, gz;
8float gxOff = 0, gyOff = 0, gzOff = 0; // jiroskop sapmaları / gyro offsets
9float roll = 0, pitch = 0, yaw = 0;
10unsigned long lastMicros;
11
12void writeReg(uint8_t reg, uint8_t val) {
13 Wire.beginTransmission(MPU_ADDR);
14 Wire.write(reg);
15 Wire.write(val);
16 Wire.endTransmission();
17}
18
19int16_t read16() {
20 uint8_t hi = Wire.read(); // önce yüksek bayt / high byte first
21 uint8_t lo = Wire.read();
22 return (int16_t)(((uint16_t)hi << 8) | lo);
23}
24
25void readMPU() {
26 Wire.beginTransmission(MPU_ADDR);
27 Wire.write(0x3B); // ACCEL_XOUT_H
28 Wire.endTransmission(false); // hattı bırakma, tekrar başlat / repeated start
29 Wire.requestFrom(MPU_ADDR, 14); // ivme 6 + sıcaklık 2 + jiroskop 6 bayt / accel 6 + temp 2 + gyro 6 bytes
30 ax = read16(); ay = read16(); az = read16();
31 tempRaw = read16();
32 gx = read16(); gy = read16(); gz = read16();
33}
34
35void calibrateGyro() {
36 const int N = 500;
37 long sx = 0, sy = 0, sz = 0;
38 for (int i = 0; i < N; i++) {
39 readMPU();
40 sx += gx; sy += gy; sz += gz;
41 delay(3);
42 }
43 gxOff = sx / (float)N;
44 gyOff = sy / (float)N;
45 gzOff = sz / (float)N;
46}
47
48void setup() {
49 Serial.begin(115200);
50 Wire.begin();
51 Wire.setClock(400000); // 400 kHz hızlı mod / 400 kHz fast mode
52 writeReg(0x6B, 0x00); // PWR_MGMT_1: uykudan uyandır / wake up
53 writeReg(0x1A, 0x03); // CONFIG: alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
54 writeReg(0x1B, 0x00); // GYRO_CONFIG: ±250 °/s
55 writeReg(0x1C, 0x00); // ACCEL_CONFIG: ±2 g
56 delay(100);
57 Serial.println("Kalibrasyon: sensoru oynatma / calibrating: keep still");
58 calibrateGyro();
59 readMPU();
60 roll = atan2(ay, az) * RAD_TO_DEG; // başlangıç açıları / initial angles
61 pitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
62 lastMicros = micros();
63}
64
65void loop() {
66 readMPU();
67 unsigned long now = micros();
68 float dt = (now - lastMicros) / 1000000.0; // saniye / seconds
69 lastMicros = now;
70
71 float accRoll = atan2(ay, az) * RAD_TO_DEG; // ivmeölçerden açı / angle from accelerometer
72 float accPitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
73 float gxRate = (gx - gxOff) / GYRO_LSB; // °/s
74 float gyRate = (gy - gyOff) / GYRO_LSB;
75 float gzRate = (gz - gzOff) / GYRO_LSB;
76
77 roll = ALPHA * (roll + gxRate * dt) + (1 - ALPHA) * accRoll; // tamamlayıcı filtre / complementary filter
78 pitch = ALPHA * (pitch + gyRate * dt) + (1 - ALPHA) * accPitch;
79 yaw += gzRate * dt; // yalnız jiroskop: zamanla kayar / gyro only: drifts over time
80
81 Serial.print("roll:"); Serial.print(roll, 1);
82 Serial.print(" pitch:"); Serial.print(pitch, 1);
83 Serial.print(" yaw:"); Serial.println(yaw, 1);
84 delay(10); // yaklaşık 100 Hz / about 100 Hz
85}| Riga di codice | Cosa fa |
|---|---|
| writeReg(0x6B, 0x00) | Fa uscire il sensore dalla modalità sleep |
| writeReg(0x1A, 0x03) | Attiva il filtro interno a circa 44 Hz |
| Wire.requestFrom(MPU_ADDR, 14) | Legge in una volta accelerazione, temperatura e giroscopio |
| calibrateGyro() | Trova l'offset del giroscopio con la media di 500 letture |
| atan2(ay, az) * RAD_TO_DEG | Calcola l'angolo roll in gradi dall'accelerometro |
| ALPHA * (...) + (1 - ALPHA) * ... | Filtro complementare: unisce giroscopio e accelerometro |
| yaw += gzRate * dt | Calcola lo yaw solo con il giroscopio; lo vedrai derivare nel tempo |
MPU6050 con ESP32: un allarme anticaduta
Sull'ESP32 il collegamento è lo stesso dell'Uno; cambiano solo i pin I2C, GPIO 21 (SDA) e GPIO 22 (SCL), e il modulo si alimenta da 3V3. Tutti gli sketch precedenti funzionano senza modifiche sull'ESP32; se vuoi, puoi indicare i pin esplicitamente con Wire.begin(21, 22). L'esempio qui sotto è un rilevatore di cadute. In un oggetto in caduta libera l'accelerometro legge quasi 0 g, perché il corpo del sensore e la massa al suo interno cadono insieme; l'urto che segue produce un picco di diversi g. Se lo sketch rileva una caduta libera di almeno 100 ms seguita, entro mezzo secondo, da un urto superiore a 2,5 g, fa suonare per un secondo un buzzer attivo collegato a GPIO 25. Una caduta libera di 100 ms corrisponde a una caduta da circa 5 cm (h = ½ × g × t²).
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6const int BUZZER_PIN = 25; // aktif buzzer / active buzzer
7const float FREE_FALL_G = 0.4; // serbest düşüş eşiği / free-fall threshold
8const float IMPACT_G = 2.5; // darbe eşiği / impact threshold
9unsigned long fallStart = 0, fallEnd = 0;
10
11void setup() {
12 Serial.begin(115200);
13 pinMode(BUZZER_PIN, OUTPUT);
14 Wire.begin(21, 22); // SDA, SCL
15 if (!mpu.begin(0x68, &Wire)) {
16 Serial.println("MPU6050 bulunamadi / not found");
17 while (true) delay(10);
18 }
19 mpu.setAccelerometerRange(MPU6050_RANGE_8_G); // darbeler için geniş aralık / wide range for impacts
20 mpu.setFilterBandwidth(MPU6050_BAND_94_HZ); // kısa darbeleri kaçırma / keep short peaks
21}
22
23void loop() {
24 sensors_event_t a, g, t;
25 mpu.getEvent(&a, &g, &t);
26 float x = a.acceleration.x, y = a.acceleration.y, z = a.acceleration.z;
27 float total = sqrt(x * x + y * y + z * z) / SENSORS_GRAVITY_STANDARD; // toplam ivme, g / total acceleration in g
28 unsigned long now = millis();
29
30 if (total < FREE_FALL_G) {
31 if (fallStart == 0) fallStart = now; // düşüş başladı / fall started
32 } else if (fallStart != 0) {
33 if (now - fallStart > 100) fallEnd = now; // en az 100 ms süren düşüş / fall of at least 100 ms
34 fallStart = 0;
35 }
36
37 if (fallEnd != 0 && now - fallEnd < 500 && total > IMPACT_G) { // düşüşten sonra 0,5 s içinde darbe / impact within 0.5 s
38 Serial.println("DUSME ALGILANDI / FALL DETECTED");
39 digitalWrite(BUZZER_PIN, HIGH);
40 delay(1000);
41 digitalWrite(BUZZER_PIN, LOW);
42 fallEnd = 0;
43 }
44 if (fallEnd != 0 && now - fallEnd >= 500) fallEnd = 0; // darbe gelmedi, sıfırla / no impact, reset
45 delay(5);
46}Partendo da qui puoi sfruttare il Wi-Fi dell'ESP32 per, ad esempio, inviare una notifica Telegram al telefono se un familiare anziano cade, oppure mostrare gli angoli in tempo reale su una pagina web. Regola le soglie con prove tue: una scatola che cade dal tavolo e un sensore al polso danno picchi diversi. Per scegliere e collegare il buzzer, leggi Cos'è un buzzer?.
MPU6050 con Raspberry Pi Pico (MicroPython)
Sul Pico non serve alcuna libreria aggiuntiva: la classe I2C integrata in MicroPython legge i registri direttamente. Collega il sensore al bus I2C0, con SDA su GP4 e SCL su GP5. Con struct.unpack trasformiamo i 14 byte in sette numeri a 16 bit con segno; ">" significa big-endian (prima il byte più significativo) e "h" intero a 16 bit con segno. Il codice stampa prima gli indirizzi I2C trovati; se nella lista non vedi 0x68, controlla i collegamenti. Per semplicità non abbiamo aggiunto la calibrazione; se serve, applica allo stesso modo il metodo della media usato nello sketch Arduino.
1from machine import Pin, I2C
2import math, struct, time
3
4MPU = 0x68
5i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
6print("Bulunan adresler / found addresses:", [hex(a) for a in i2c.scan()])
7
8i2c.writeto_mem(MPU, 0x6B, b"\x00") # uykudan uyandır / wake up
9i2c.writeto_mem(MPU, 0x1A, b"\x03") # alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
10i2c.writeto_mem(MPU, 0x1B, b"\x00") # jiroskop ±250 °/s / gyro ±250 °/s
11i2c.writeto_mem(MPU, 0x1C, b"\x00") # ivmeölçer ±2 g / accelerometer ±2 g
12roll = pitch = 0.0
13last = time.ticks_us()
14
15while True:
16 data = i2c.readfrom_mem(MPU, 0x3B, 14)
17 ax, ay, az, t, gx, gy, gz = struct.unpack(">hhhhhhh", data) # büyük endian, işaretli / big-endian, signed
18 now = time.ticks_us()
19 dt = time.ticks_diff(now, last) / 1000000
20 last = now
21 acc_roll = math.degrees(math.atan2(ay, az))
22 acc_pitch = math.degrees(math.atan2(-ax, math.sqrt(ay * ay + az * az)))
23 roll = 0.98 * (roll + gx / 131 * dt) + 0.02 * acc_roll # tamamlayıcı filtre / complementary filter
24 pitch = 0.98 * (pitch + gy / 131 * dt) + 0.02 * acc_pitch
25 temp = t / 340 + 36.53 # °C
26 print("roll {:.1f} pitch {:.1f} T {:.1f}".format(roll, pitch, temp))
27 time.sleep_ms(10)Idee di progetto con l'MPU6050
- Livella digitale: mostra gli angoli roll e pitch su un display OLED con una bolla che si muove.
- Servo comandato dal movimento: quando inclini il sensore in mano, un servomotore ruota allo stesso angolo; ideale per un braccio robotico o una testa per fotocamera.
- Gioco a inclinazione: gioca a Pong o a un labirinto inclinando la scheda invece di usare un joystick.
- Robot autobilanciato: elabora l'angolo pitch con un PID e tieni in piedi il robot con motori DC pilotati da un L298N.
- Contapassi: misura la camminata contando i picchi regolari dell'accelerazione totale.
- Registratore di vibrazioni: misura le scosse di una macchina o della lavatrice e dai un avviso quando si supera una soglia.
Errori comuni e soluzioni
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| begin() restituisce false ("MPU6050 not found") | Errore di cablaggio, indirizzo sbagliato o chip clone | Trova l'indirizzo con uno scanner I2C; se WHO_AM_I non è 0x68 (ad esempio 0x70), usa il codice senza libreria |
| Tutti i valori sono 0 | Il sensore è in sleep | Scrivi 0 nel registro 0x6B |
| Valori a -1 o bloccati | Filo allentato, bus I2C lungo | Accorcia i fili e salda i pin |
| L'angolo deriva da fermo | Offset del giroscopio non corretto | Calibra all'avvio con il sensore fermo |
| L'angolo salta durante il movimento | Si usa solo l'accelerometro | Aggiungi un filtro complementare |
| Lo yaw continua a derivare | L'MPU6050 non ha bussola | Aggiungi un magnetometro come il QMC5883L o usa un sensore a 9 assi |
| Il roll impazzisce quando il pitch si avvicina a ±90° | Singolarità degli angoli di Eulero | Evita quella zona o usa l'uscita in quaternioni del DMP |
Nonostante il prezzo basso, l'MPU6050 apre le porte alla misura del movimento: prima conosci i valori grezzi, poi calcola gli angoli e infine rendili fluidi con un filtro. Per scoprire altri sensori I2C e i loro usi, dai un'occhiata alla Guida ai sensori Arduino. Nell'app BlueGrays trovi progetti di controllo servo, display I2C, joystick e robot con schema elettrico e codice passo dopo passo, da combinare con l'MPU6050.
Domande frequenti
A cosa serve l'MPU6050?
L'MPU6050 misura l'inclinazione, la velocità di rotazione e l'accelerazione di un oggetto. Si usa in robot autobilanciati, droni e gimbal, contapassi, rilevamento di cadute e urti e nei giochi controllati con il movimento.
L'indirizzo dell'MPU6050 è 0x68 o 0x69?
L'indirizzo è 0x68 quando il pin AD0 è libero o collegato a GND, e 0x69 quando è collegato a 3,3 V. Sulla scheda GY-521 AD0 è portato a GND da una resistenza, quindi l'indirizzo predefinito è 0x68. Per esserne sicuro, esegui uno scanner I2C.
L'MPU6050 funziona a 5 V?
Il chip MPU6050 regge al massimo 3,46 V, ma grazie al regolatore della scheda GY-521 il pin VCC si può alimentare a 5 V. Le linee I2C restano a livello 3,3 V, che l'Arduino Uno legge senza problemi. Alle schede nude senza regolatore non bisogna dare 5 V.
Come si calcola l'angolo con l'MPU6050?
Con il sensore fermo, gli angoli si ricavano dall'accelerometro con roll = atan2(ay, az) e pitch = atan2(−ax, √(ay² + az²)). Per risultati precisi in movimento si integra nel tempo la velocità angolare del giroscopio e la si combina con l'angolo dell'accelerometro tramite un filtro complementare o di Kalman.
L'MPU6050 può misurare lo yaw?
Per brevi periodi sì: lo yaw si calcola integrando la velocità angolare dell'asse Z. Ma poiché l'MPU6050 non ha un magnetometro, lo yaw deriva nel tempo e non conosce la direzione assoluta (il nord). Per una direzione stabile serve una bussola come il QMC5883L o una IMU a 9 assi.
Che differenza c'è tra MPU6050 e MPU9250?
L'MPU6050 è un sensore a 6 assi con accelerometro e giroscopio. L'MPU9250 aggiunge un magnetometro a 3 assi, quindi è a 9 assi e può misurare lo yaw senza deriva; supporta anche l'SPI. Poiché l'MPU9250 non è più prodotto, nei nuovi progetti si preferiscono successori come l'ICM-20948.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
Utilizzo del servomotore
Progetto di base che posiziona il servomotore su angoli di 0°, 90° e 180° in sequenza. Insegna la libreria dei servo e la logica di controllo degli angoli.

SG90 Servocomando angolare con potenziometro
Controllo del servomotore (SG90) con il potenziometro L'obiettivo principale di questo progetto è controllare con precisione la posizione angolare di un servomotore in tempo reale utilizzando un'unità di ingresso analogica, il potenziometro. Il progetto è un esempio di ingegneria di base per comprendere la logica della conversione analogico-digitale (ADC) e la mappatura dei segnali. Logica di funzionamento: Lettura dei dati analogici: Quando l'utente ruota il potenziometro, un segnale di tensio

Servocomando con joystick
Progetto di pan-tilt che controlla in modo indipendente due servomotori sugli assi X e Y con un modulo joystick. Insegna la logica dell'integrazione joystick-servo e l'inseguimento della posizione.

Servomotore ESP32 (controllo tramite potenziometro)
In questo progetto controlliamo un servomotore SG90 tramite un potenziometro. Regoliamo l'angolo del servomotore mappando il valore analogico letto dal potenziometro su un intervallo compreso tra 0 e 180 gradi. Grazie alla libreria ESP32Servo, qualsiasi GPIO dell'ESP32 può generare un segnale PWM. Si tratta di un metodo di controllo fondamentale per bracci robotici, gimbal per telecamere e meccanismi di porte automatiche.

Gioco Pong - SSD1306
Il classico gioco del Pong costruito con Arduino e display OLED SSD1306, dotato di un'intelligenza artificiale (CPU) autonoma che segue istantaneamente i movimenti della palla e reagisce in base alla

Utilizzo dello schermo LCD con I2C
Grazie al modulo I2C, il progetto che stampa messaggi controllando lo schermo LCD con solo 2 cavi (SDA, SCL). Insegna come salvare i pin con il protocollo I2C.

Schermo LCD I2C per ESP32 (16x2)
In questo progetto visualizziamo del testo collegando un display LCD a 16x2 caratteri all'ESP32 tramite il protocollo I2C. Grazie all'I2C possiamo controllare il display utilizzando solo 2 pin di dati (SDA e SCL); si elimina così lo spreco dei 6+ pin tipici del collegamento parallelo classico. Il codice stampa un messaggio fisso sulla prima riga e un contatore che aumenta ogni secondo sulla seconda riga. Inoltre, all'inizio, eseguendo lo scanner I2C, stampiamo l'indirizzo del display sul Serial

Robot che evita gli ostacoli
Che ne dite di costruire un veicolo intelligente che trova la propria strada? L'Obstacle Avoiding Robot scruta costantemente l'ambiente circostante grazie al sensore a ultrasuoni posto davanti a lui.
Altri articoli
Impara a collegare l'accelerometro e giroscopio MPU6050 ad Arduino, leggere i valori grezzi, calibrare il sensore, calcolare l'angolo di inclinazione e ripulirlo con un filtro complementare; in più un allarme anticaduta con ESP32 e il codice per il Pico.

