Site icon Meccanismo Complesso

Arduino: misuriamo il campo magnetico terrestre con il magnetometro HMC5883L

Il magnetometro HMC5883L

Questo componente (un piccolo chip) HMC5883L prodotto dalla Honeywell, basa il suo funzionamento sulla tecnologia AMR (Anisotropic Magnetoresistive) e ci permette di poter misurare sia la direzione che l’ampiezza del campo magnetico terrestre. Questo magnetometro HMC5883L ha al suo interno 3 sensori magneto-resistivi disposti su 3 assi perpendicolari (assi cartesiani x,y e z). Qui potete trovare il datasheet del componente.

Fig.1: Il chip HMC5883L della Honeywell

Il campo magnetico ha effetto su questi sensori modificando in qualche modo la corrente che li attraversa. Applicando una scala a questa corrente, possiamo conoscere la forza magnetica (espressa in Gauss) esercitata su ciascun sensore.

Il componente HMC5883L comunica con Arduino attraverso il protocollo I2C, un protocollo molto semplice da usare.

Per il nostro esempio con Arduino io ho acquistato la breakout board del HMC5883L distribuita dalla Sparkfun in cui è visibile al centro il chip integrato.

Triple Axis Magnetometer Breakout – HMC5883L

Sul mercato sono disponibili moltissime altre breakout board su cui è integrato questo chip, alcune davvero molto economiche.

HMC5883L BMP180 GY 87 ACC
SODIAL (R) Modulo L3G4200D ADXL345 HMC5883L BMP085

Lo schema elettrico

La libreria HMC5884L per Arduino

In internet è possibile trovare numerose librerie programmate specificamente per l’utilizzo di questo sensore. Per gli esempi trattati in questo articolo ho scelto di utilizzare una libreria prelevata dalla LoveElectronic un po’ di tempo fa (anche se attualmente non riesco più a ritrovare il sito) chiamata appunto HMC5884L.

Clicca qui per fare il download della libreria. Una volta scaricato il file zip, estraete il contenuto all’interno della directory Program Files > Arduino > LIbraries (se sei su Windows), cioè una cartella nominata HMC5883L.

Fig.4: File contenuti all’interno della libreria HMC5883L

Una volta estratto il contenuto fate partire l’IDE di Arduino. Se tutto è stato installato correttamente troverete un nuovo esempio caricato all’interno dell’IDE (come mostrato nella figura 5).

Fig.5: Se l’installazione è andata correttamente troverete l’esempio Simple all’interno di HMC5883L

Un sito in cui è presentato un ottimo tutorial con questa libreria è questo.

Il miglior modo per imparare ad utiliizzare questa libreria è quella di utilizzarla in semplici esempi, durante i quali verranno spiegati i comandi e le funzioni principali, il loro funzionamento e come si usano. A tale scopo in questo articolo faremo due esempi, per prima cosa realizzeremo una bussola digitale, poi utilizzeremo HMC5883L come un vero e proprio magnetometro, raccogliendo dei dati per poi utilizzarli nella rappresentazione di un campo vettoriale tramite MATLAB.

Realizziamo una bussola digitale

Tutti quanti hanno familiarità con questo genere di oggetti. Una piccola scatoletta cilindrica con all’interno un ago di materiale ferroso che risentendo del campo magnetico terrestre, si allinea secondo le linee di campo che percorrono la superficie della terra, indicando così il nord.

Quello che vogliamo realizzare con Arduino è la creazione di una bussola che ci darà il valore 0° quando si punta il sensore verso il nord magnetico, e 180° quando invece stiamo puntando il sud.

Il codice che stiamo utilizzando è molto comune in rete con infinite piccole variazioni. Lo propongo perchè è unn esempio molto utile per capire come utilizzare questo sensore, molto semplice nel suo insieme e adatto a prendere confidenza con i comandi della libreria HMC5883L

Per prima cosa dobbiamo importare la libreria HMC5883L.

#include <HMC5883L.h>

Dato che la scheda HMC5883L comunica con Arduino attraverso il protocollo I2C, è necessario importare anche la libreria Wire (leggi qui per maggiori informazioni).

#include <wire.h>

Una volta incluse tutte le librerie necessarie, dichiariamo come variabile globale l’istanza di HMC5883L

HMC5883L compass;

Adesso possiamo cominciare a definire il contenuto dei due metodi setup() e loop() onnipresenti in qualsiasi sketch di Arduino.

Cominciamo come logico, dal metodo setup(). Per prima cosa attiviamo il protocollo di comunicazione I2C tra Arduino e il magnetometro.

void setup() {
    Wire.begin();

Inoltre, dato che abbiamo bisogno di visualizzare da qualche parte i valori delle letture del magnetometro, utilizzeremo la comunicazione seriale tra Arduino e un PC. Specifichiamo quindi

Serial.begin(9600);
Serial.println("Serial started");

Inizializzate tutte le connessioni, adesso possiamo inizializzare anche il magnetometro definendo:

compass = HMC5883L();

Il passo successivo sarà quello di configurare il sensore a seconda delle nostre esigenze. Per prima cosa è necessario definire il guadagno (scala di risposta) su cui far lavorare il nostro magnetometro.

Serial.println("Setting scale to +/- 1.3Ga");
int error = compass.SetScale(1.3);
if(error != 0)
    Serial.println(compass.GetErrorText(error));
Serial.println("Setting measurement mode to continuous.");
error = compas.SetMeasurementMode(Measurement_Continuous);
if(error != 0)
   Serial.println(compass.GetErrorText(error));

Con queste righe di codice abbiamo impostato il guadagno a 1.3 Ga (fondo scala), cioè le nostre misure dovranno essere comprese tra valori di -1.3 e 1.3 Ga.

Le scale possibili di guadagno impostabili sul nostro magnetometro sono:  0.88, 1.3, 1.9, 2.5, 4.0, 4.7, 5.6 e 8.1 gauss. Inutile dire che se le vostre minure rientrano entro un certo intervallo, cercate di selezionare la scala minore possibile che lo contiene, poichè la precisione della misura effettuata dalla vostra scheda sarà maggiore.

Adesso cominciamo a definire il contenuto della funzione loop(). Il codice scritto all’interno di questa funzione verrà eseguito in continuazione, e quindi ad ogni sua esecuzione verrà effettuata una misurazione da parte del sensore.

void loop(){
   MagnetometerRaw raw = compass.ReadRawAxis();

La funzione ReadRawAxis() restituisce il valore ottenuto direttamente dal magnetometro. Quindi i valori ottenuti in questo modo non hanno alcun riferimento al vero valore della forza del campo magnetico, ma sono solo proporzionali ad esso. Quindi se sei interessato al vero valore in gauss del campo magnetico non dovresti prendere in considerazione questa funzione, ma sostituirla con la funzione ReadScaledAxis().

Nel nostro caso però noi siamo interessati a simulare l’orientamento dell’ago magnetico di una bussola, quindi i valori reali non ci interessano. Quindi possiamo tranquillamente utilizzare i valori grezzi di lettura.

Ricordiamoci che il nostro magnetometro è in grado di rilevare contemporaneamente le misure sui tre assi cartesiani. Per ottenere questi valori, basta richiamare i seguenti valori appartenenti alla variabile oggetto MagnetometerRaw in cui li abbiamo immagazzinati. Ecco un esempio di come possiamo ottenere i 3 valori ciascuno per ogni asse (righe da non inserire nel codice).

int xAxis = raw.XAxis;
int yAxis = raw.YAxis;
int zAxis = raw.ZAxis;

Se avessimo voluto invece utilizzare i valori reali riportati direttamente in scala (misure in Gauss). (righe da non inserire nel codice)

MagnetometerScaled scaled = compass.ReadScaledAxis();
int xAxis = scaled.XAxis;
int yAxis = scaled.YAxis;
int zAxis = scaled.ZAxis;

Adesso definiamo l’ago della bussola all’interno della funzione loop().

float heading = atan2(raw.YAxis, raw.XAxis);
if(heading < 0)
    heading += 2*PI;

dato che l’angolo che otteniamo da tale formula è in radianti, convertiamola in gradi che è un formato a noi molto più familiare e leggibile.

float headingDegrees = heading * 180/M_PI;

Adesso non ci resta altro che visualizzare il valore ottenuto sul nostro PC collegato ad Arduino tramite comunicazione seriale.

Serial.println(headingDegrees);
delay(1000);

Ho aggiunto delay() in modo da effettuare una misura al secondo (1000 ms), ma potete variare questa misura a vostro piacimento.

Ecco il codice al completo:

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;
 
void setup()
{
   Wire.begin();
   Serial.begin(9600);
   compass = HMC5883L();

   Serial.println("Setting scale to +/- 1.3Ga");
   int error = compass.SetScale(1.3);
   if(error != 0)
     Serial.println(compass.GetErrorText(error));

   Serial.println("Setting measurement mode to continuous");
   error = compass.SetMeasurementMode(Measurement_Continuous);
   if(error != 0)
   Serial.println(compass.GetErrorText(error));
}

void loop()
{
   MagnetometerRaw raw = compass.ReadRawAxis();
   float heading = atan2(raw.YAxis, raw.XAxis);
   if(heading < 0)
      heading += 2*PI;
   float headingDegrees = heading * 180/M_PI;
   Serial.println(headingDegrees);
   delay(1000);
}

Adesso collegando Arduino al PC e aprendo una comunicazione seriale potete controllare il funzionamento della vostra bussola digitale. Ruota la breakout board fin quando non otterrai il valore 0. Una volta ottenuto questo valore scoprirai la direzione del nord (magnetico).

Fig.6: Monitor seriale

La declinazione magnetica

Il campo magnetico che avvolge il globo terrestre non è nè perfetto nè uniforme, ma è soggetto a continue variazioni sia nello spazio che nel tempo. Questo effetto è chiamato declinazione magnetica. A tal proposito c’è una bellissima GIF animata che voglio proporvi che presenta la variazione del campo magnetico durante questi ultimi 4 secoli (1590-1990).

Per quanto riguarda la nostra bussola digitale è possibile tenere conto di questo effetto modificando leggermente la formula utilizzata nell’esempio precedente.

Per prima cosa dobbiamo ricavarci il valore della declinazione magnetica della posizione in cui stiamo effettuando la misura. Esiste in internet un bellissimo sito in grado di fornirci in tempo reale proprio il valore della declinazione magnetica di cui abbiamo bisogno (www.magnetic-declination.com). Questo sito vi darà immediatamente la declinazione magnetica della posizione in cui sei collegato. Ecco il mio esempio sotto:

Fig.7: il valore della declinazione magnetica a Roma al momento in cui sto scrivendo l’articolo.

Dal casella che appare al centro della nostra mappa siamo interessati principalmente al valore:

Adesso connettiamoci su WolframAlpha, un bellissimo sito per il calcolo e le informazioni scientifiche online. Grazie ad esso convertiremo il valore della declinazione magnetica in radianti: nel campo di immissione digitiamo

(2° 38') in radians
Fig.8: il sito WolframAlpha permette di fare molti calcoli matematici e conversioni di unità di misura online
Fig.9: ecco il risultato della conversione in milliradianti

Quindi all’interno della funzione loop() aggiungiamo il seguente codice:

float declinationAngle = 45.96/1000;
heading += declinationAngle;

Questo perchè abbiamo ottenuto una declinazione EAST, se invece la declinazione è WEST avremmo dovuto scrivere:

heading -= declinationAngle;

Ed infine

if(heading <0)
   heading += 2*PI;
if(heading > 2*PI)
   heading -= 2*PI;
float headingDegrees = heading * 180/M_PI;

Un altro esempio: visualizziamo il campo magnetico sul nostro tavolino

Adesso sviluppiamo un altro esempio, a mio parere un po’ più divertente, anche se più laborioso.

In questo esempio faremo una serie di misure sul tavolino vicino al nostro computer per visualizzare le linee di campo che lo attraversano. Nella seconda fase dell’esempio introdurremo un magnete vicino alla zona in cui abbiamo effettuate le misure precedenti e rieffettueremo le misure nuovamente. Sarà interessante osservare l’effetto che introdurrà il magnete sulle linee di campo che attraversano il nostro tavolino.

Per l’esempio che stiamo considerando prenderemo in considerazione solo le componenti vettoriali del campo magnetico sull’asse X e sull’asse Y, visualizzando il campo magnetico che attraversa la superficie del nostro tavolino.

Per prima cosa prendiamo in considerazione il codice per Arduino

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;
int i;
float X_tot, Y_tot, Z_tot;
float X,Y,Z;
void setup()
{
   Wire.begin();
   Serial.begin(9600);
   compass = HMC5883L();
 
   Serial.println("Setting scale to +/- 1.3Ga");
   int error = compass.SetScale(1.3);
   if(error != 0)
     Serial.println(compass.GetErrorText(error));
 
   Serial.println("Setting measurement mode to continuous");
   error = compass.SetMeasurementMode(Measurement_Continuous);
   if(error != 0)
     Serial.println(compass.GetErrorText(error));
 
   i = 0;
   X_tot = 0;
   Y_tot = 0;
   Z_tot = 0;
   X = 0; Y = 0; Z = 0;
}

void loop()
{
   MagnetometerRaw raw = compass.ReadRawAxis();
   if(i<499){
     X_tot += raw.XAxis;
     Y_tot += raw.YAxis;
     Z_tot += raw.ZAxis;
   }else{
     X = X_tot/500;
     Y = Y_tot/500;
     Z = Z_tot/500;
     X_tot = 0; Y_tot = 0; Z_tot = 0;
     i = 0;
     Serial.print(i+":t");
     Serial.print(X);
     Serial.print(" ");
     Serial.print(Y);
     Serial.print(" ");
     Serial.print(Z);
     Serial.println(" ");
     delay(2000);
   }
   i++;
}

come potete vedere dal codice ho utilizzato le misure raw, ma se volete fare un lavoro più preciso vi consiglio di utilizzare le misure scaled. Inoltre ho fatto in modo che il valore visualizzato sul PC serialmente, sia la media ottenuta su 500 valori. Ho fatto vari tentativi e ho visto che con questa media si ottengono valori abbastanza ripetitivi. Incrementando o decrementando il numero dei campioni per media ottengo risulati peggiori (nel vostro caso potete fare varie prove).

Adesso passiamo alla misura vera e propria.

Per prima cosa ho preso un foglio a quadretti e ho disegnato su di esso 35 quadrati aventi ciascuno la stessa dimensione della breakout board della Sparkfun. Ho creato così una matrice di 5×7 quadrati, e poi ho numerato ciascuno di essi in ordine crescente.

Fig.10: Un foglio a quadretti è una buona base per tracciare una matrice di punti di misura.

Poi ho messo il foglio sul tavolino fissandolo in modo che non si possa muovere su di esso (con del nastro adesivo, o dei pesetti). Una volta fatto questo ho effettuato delle misure del campo magnetico su ciascun quadratino, annotandomi sia la forza del campo magnetico dell’asse X che dell’asse Y. (N.B. i valori letti molto spesso oscilleranno, cercate di vedere il valore che ricorre più spesso)

Alla fine otterrete una tabella di valori. Io vi mostro la tabella dei valori che ho ottenuto io sul mio tavolino e che poi saranno quelli visualizzati nell’esempio.

XYZ
1-27-348-386
2-17-347-388
314-350-389
414-351-390
5-5-360-393
6-20-350-377
7-10-345-380
82-350-387
927-353-390
1017-356-394
11-46-325-368
12-3-334-380
139-340-386
14-26-340-388
15-16-347-400
160-318-232
1717-340-368
1820-347-385
193-340-401
2021-340-408
21-27-394-308
22-10-350-378
23-5-334-398
24-12-338-404
25-48-326-423
26-47-350none
271-346none
281-343none
2938-343none
30-35-330none
31-80-400none
321-346none
33-23-342none
3415-340none
35-107-410none

Una volta ottenuti tutti i valori, apro una sessione su MATLAB e comincio a definire una matrice SX e SY contenenti i valori misurati rispettivamente per X che per Y. Queste due matrici SX e SY hanno dimensione 5×7 ed i valori vanno inseriti al loro interno nella stessa disposizione che abbiamo sul foglio a quadretti, in modo che la distribuzione spaziale delle misure venga rispettata.

>>SX = [  -27 -17 14 14 -5; 
          -20 -10 2 27 17; 
          -46 -3 9 -26 -16; 
           0 17 20 3 21; 
          -27 -10 -5 -12 -48; 
          47 1 1 38 -35; 
          -80 1 -23 15 -107];
>>SY = [  -348 -347 -350 -351 -360; 
        -350 -345 -350 -353 -356; 
        -352 -334 -340 -340 -347; 
        -318 -340 -347 -340 -340; 
        -394 -350 -334 -338 -326; 
        -350 -346 -343 -343 -330; 
        -400 -346 -342 -340 -410]

definiamo inoltre la disposizione spaziale X e Y di ciascun quadrato (misura).

>>x = linspace(0,5,5); 
>>y = linspace(0,7,7);
>>[X,Y] = meshgrid(x,y);
>> quiver(X,Y,SX,SY);

e finalmente otteniamo la visualizzazione dei vettori del campo magnetico. La figura che otteniamo è invertita rispetto alla foto del tavolino (la cella 1 è in basso a sinistra)

Fig.11: Il campo magnetico terrestre rappresentato vettorialmente sul piano del tavolino

Adesso inseriamo un magnete alla sinistra del foglio a circa 7 cm da esso e in corrispondenza del centro del foglio.

Fig.8: il magnete è posizionato a destra della matrice

Rieffettuiamo tutte le misure per ciascun quadratino come abbiamo fatto in precedenza, fino ad ottenere la seguente tabella.

XYZ
1-109-303-383
2-108-284-391
3-130-322-394
4-174-188-412
5-244-9-446
6-124-290-380
7-158-350-380
8-185-267-394
9-329-182-412
10-756-147-417
11-125-294-363
12-127-323-400
13-199-330-388
14-403-275-399
15-975-240-475
16-73-321-243
17-105-356-365
18-178-398-385
19-406-450-387
20-778-820-332
21-98-474-343
22-106-370-373
23-154-420-390
24-157-517-386
25-390-736-290
26-85-373-382
27-93-394-385
28-89-430-381
29-121-500-380
30-113-650-430
31-74-375-380
32-76-465-378
33-38-422-381
34-65-500-390
35-160-523-400

Adesso, sempre con MATLAB definiamo due matrici 5×7 VX e VY contenenti le nuove misure, e alla fine rilanciamo la rappresentazione grafica.

>>VX = [ -109 -108 -130 -174 -244;
         -124 -158 -185 -329 -756;
         -125 -127 -199 -403 -975;
         -73 -105 -178 -406 -778;
         -98 -106 -154 -157 -390;
         -85 -93 -89 -121 -113;
         -74 -76 -38 -65 -160 ]
>>VY = [ -303 -284 -322 -171 -9;
         -290 -350 -267 -182 -147;
         -294 -323 -330 -275 -240;
         -321 -356 -398 -450 -820;
         -474 -370 -420 -517 -736;
         -373 -394 -430 -500 -650;
         -375 -465 -422 -500 -523 ]

Con il comando hold on possiamo sovrapporre la nuova rappresentazione con quella precedente in modo da visualizzare meglio le variazioni al campo magnetico terrestre introdotte con l’avvicinamento di un magnete.

>> quiver(X,Y,SX,SY);
>> hold on
>> quiver(X,Y,VX,VY);
Fig.12: Il campo vettoriale senza magnete (verde) e quello con il magnete (blu)

Come possiamo vedere l’effetto è abbastanza considerevole in prossimità del bordo destro e va via via diminuendo con l’allontanarsi dal magnete.

Conclusioni

Questo piccolo articolo è solo una piccola introduzione alle grandi potenzialità di questo sensore. Molto interessante sarebbe l’estendere l’esempio precedente a 3 dimensioni considerando anche la Z. Un’altra buona idea sarebbe quella di poter visualizzare la variazione nel tempo del campo magnetico.

Ma questo lo lascio a voi! Arrivederci al prossimo articolo.

Exit mobile version