Feb 172019
 

Visto che in un prossimo progetto vedremo un sistema di monitoraggio dell’impianto fotovoltaico, ho bisogno di misurare le correnti che transitano dai pannelli fotovoltaici e da / verso il pacco batterie. Si tratta di correnti importanti, il mio inverter è in grado di far transitare la bellezza di 200A anche se io ho delle batterie da 100A ed ho limitato la corrente massima via software. I moduli che vi presento oggi si basano sulla famiglia di integrati ACS758 e permetto di “leggere” il passaggio di una corrente sia continua che alternata, uno è bidirezionale da 150A da mettere fra inverter e pacco batterie, l’altro monodirezionale da 100A da mettere fra il combinatore solare e l’inverter.

Il funzionamento è molto semplice, non dobbiamo far altro che collegare i due capi della tensione in transito, alimentare il modulo con una tensione compresa fra 3 e 5.5V ed andare a leggere il risultato ottenuto. Tale risposta dipende dal tipo di modulo, se mono o bidirezionale e da altri piccoli dettagli che ora vedremo.

Bidirezionale

In questo caso la tensione fornita in risposta equivale a VCC/2 quando non transita alcuna corrente, ossia alimentando il modulo a 3.3V dovrei leggere una tensione di 1.65. Se il valore supera gli 1.65V significa che c’è una certa corrente che va in verso, mentre se otteniamo un valore inferiore a 1.65 significa che la corrente scorre in senso opposto. Si, ma quanta corrente? Questo modulo ha una sensibilità di 8.6mV/A. Questo significa che  ad esempio che al limite massimo di 150A avrò 150*8.6=1290mV, ossia 1.29V che sommati agli 1.65 del “punto zero” fanno 2.94V. Io per testare lo sketch utilizzerò un alimentatore da laboratorio che mi fornisce un massimo di 5A. In quel caso dovrei ottenere una variazione dal punto zero di 43mV (8.6*5) quindi, in base al senso di scorrimento della corrente, dovrei leggere 1.607 o  1.693V.

Monodirezionale

In questo caso la tensione fornita in risposta equivale a VCC*0.12 quando non transita alcuna corrente, ossia alimentando il modulo a 3.3V dovrei leggere una tensione di 0.396V. Ogni incremento da questo valore di base corrisponde ad una corrente in transito. Si, ma quanta corrente? Questo modulo ha una sensibilità tripla rispetto al precedente in quanto effettua la misura in una sola direzione ed è da “soli” 100A il che equivale a di 25.6mV/A. Questo significa che  ad esempio che al limite massimo di 100A avrò 100*25.6=2560mV, ossia 2.56V che sommati agli 0.396 del “punto zero” fanno 2.956V. Con il mio alimentatore da laboratorio al massimo di 5A dovrei ottenere una variazione dal punto zero (0.396V) di 3.3*25.6=84.48mV per un totale di 0.48V.

Questi sono dati teorici e basati su uno schema riassuntivo che ho trovato sul sito del rivenditore, ma ora dobbiamo applicarli sul campo e vedere come si comportano. Bene, allora non dobbiamo far altro che collegare questo modulo ad Arduino per cominciare a fare un po’ di prove. Visto che sono in possesso di due moduli, proverò ad usare sia Arduino UNO che un clone di Arduino M0 Mini (WemOS M0) così possiamo vedere le differenze fra un sistema a 5V e 3.3V e possiamo vedere quali differenze di misurazione ci saranno utilizzando le due schede.

Collegamenti

I collegamenti sono estremamente semplici. Per orientarci meglio guardiamo la foto qui sotto e facciamo un esempio di collegamento fra il pacco batterie e l’inverter.

Per prima cosa dobbiamo decidere se il flusso di corrente lo intendiamo positivo quando fluisce verso l’inverter o verso il pacco batterie. Decidiamo in maniera arbitraria che intendiamo flusso positivo la corrente che si dirige verso le batterie e negativo quello che dalle batterie si porta verso l’inverter. Quindi, guardando la figura qui sopra, in B mettiamo il capo positivo proveniente dall’inverter e in A mettiamo il capo positivo che giunge al pacco batterie.

Il secondo collegamento da fare è con i piccoli pad che ci sono in basso a destra ove possiamo decidere se saldare direttamente dei fili o un più comodo connettore a 3 pin, cosa che ho fatto. Nel numero 1 e 2 troviamo rispettivamente VCC e GND, quindi di fatto si tratta dell’alimentazione del modulo che può funzionare con una tensione compresa fra 3 e 5.5V. Il numero 3 invece ci restituisce un segnale analogico proporzionale alla quantità di corrente che attraversa l’intergrato.

Due calcoli teorici

Prima di collegare il tutto cerchiamo di fare un piccolo sforzo matematico in quanto dobbiamo convertire il segnale analogico in uscita dal modulo in un valore di corrente che transita attraverso il medesimo. Ovviamente i calcoli su Arduino UNO ed Arduino M0 saranno differenti. Partiamo dai dati di sensibilità forniti dal rivenditore che sono, per il modulo bidirezionale:

5.0V – 13.3 mV/A

3.3V – 8.6 mV/A

Prendiamo per primo il funzionamento a 3.3V. Per ogni Ampere, il modulo restituisce una tensione di 8.6mV. All’estremo massimo di lettura, ossia 150A, abbiamo 1290mV, ossia 1.29V. Quindi il segnale in uscita varierà fra + e – 1.29V rispetto il punto di partenza che è VCC/2, ossia 1.65V. Il range del segnale in uscita è quindi compreso fra 0.36 e 2.94V. Ora, Arduino M0 permette di campionare 4096 valori, per cui i 3.3V massimi vengono suddivisi in 4096 parti. La risoluzione di lettura è perciò di circa 0.8mV per ogni singola suddivisione. A partire da questi dati possiamo calcolare quello che ci pare. Ad esempio potremmo chiederci quanto varia la lettura di Arduino per ogni Ampere di corrente che transita. Se il sensore fornisce una variazione dl 8.6mV e Arduino ha una risoluzione di 0.8mV, significa che il valore letto da Arduino cambia di 8.6/0.8 di circa 10-11. Ad esempio se avessimo una corrente di 4A che transita in senso inverso dalle batterie all’inverter che valore leggerà Arduino? Semplice, sarà il punto medio, ossia 4096/2, a cui dobbiamo togliere 4*8.6/0.8, quindi 2048-43=2005.

Rifacciamo tutti i calcoli con Arduino UNO e vediamo cosa succede. Faccio un copia-incolla del testo qui sopra e modifico solamente i dati.

Prendiamo per secondo funzionamento a 5V. Per ogni Ampere, il modulo restituisce una tensione di 13.3mV. All’estremo massimo di lettura, ossia 150A, abbiamo 1995mV, ossia 2V (arrotondati). Quindi il segnale in uscita varierà fra + e – 2V rispetto il punto di partenza che è VCC/2, ossia 2.5V. Il range del segnale in uscita è quindi compreso fra circa 0.5 e 4.5V. Ora, Arduino UNO permette di campionare 1024 valori, per cui i 5V massimi vengono suddivisi in 1024 parti. La risoluzione di lettura è perciò di circa 4.88mV (a confronto degli 0.8 di M0). A partire da questi dati possiamo calcolare quello che ci pare. Ad esempio potremmo chiederci quanto varia la lettura di Arduino per ogni Ampere di corrente che transita. Se il sensore fornisce una variazione di 13.3mV e Arduino ha una risoluzione di 4.88mV, significa che il valore letto da Arduino cambia di 13.3/4.8 di circa 2.8 (ma essendo un valore digitale sarà 2 o 3 a seconda del rumore di fondo). Ad esempio se avessimo una corrente di 4A che transita in senso inverso dalle batterie all’inverter che valore leggerà Arduino? Semplice, sarà il punto medio, ossia 1024/2, a cui dobbiamo togliere 4*13.3/4.8, quindi 512-11=501.

Da questi pochi dati potremmo dire che Arduino M0 ha una precisione di circa 4 volte superiore, ma attenzione perché anche il rumore aumenta in maniera proporzionale.

Lo sketch

Qui le difficoltà sono davvero minime. Proprio per questo cerchiamo di renderci la vita un pochino più complicata ed usiamo la compilazione condizionale per fare in modo che lo stesso identico sketch venga compilato correttamente sia su Arduino UNO che su M0. Ovviamente dopo aver scritto la frase “le difficoltà sono davvero minime” sono cominciate le prime bestemmie. Con M0 non ricevevo alcun output seriale e nemmeno il classico esempio con il lampeggio del led sembrava funzionare. Ho perciò lasciato in funzione l’esempio che fa lampeggiare il led sulla porta 13 ed ho collegato l’oscilloscopio sulla relativa porta. Ok, funziona, vedo il segnale che sale e scende nel tempo per cui molto banalmente non c’è un led collegato alla porta 13, ma io non lo sapevo. Comunque sia Arduino funziona! Ma l’output seriale non va quindi….cerca cerca cerca, e ti scopro che la classica Serial non è connessa alla porta USB per cui se volete l’output sulla porta USB dovete cambiare dispositivo, anziché Serial dovete usare SerialUSB. Ciò è probabilmente legato al fatto che il microcontrollore montato su questa scheda (SAMD21) ha 6 porte seriali riprogrammabili, che possono essere trasformate da UART a I2C o SPI a seconda delle esigenze. Cavoli, troppo scomodo però, come faccio a fare un singolo sketch che funziona sia su UNO che M0 se devo usare dispositivi differenti per comunicare sulla seriale? Beh, avevo già deciso di usare la compilazione condizionale per cui andiamo a sfruttarla anche per questo compito. Creiamo un nuovo dispositivo “virtuale” che a sua volta sostituirà l’uno o l’altro in fase di compilazione a seconda della scheda su cui viene compilato lo sketch.

Serial.begin(9600);
while (!Serial) {}
Serial.println(“STARTING READER…. “);

Questo qui sopra è un classico esempio di inizializzazione della porta seriale su Arduino UNO. Ottimo, ma abbiamo detto che su M0 dobbiamo sostituire la Serial con SerialUSB. Quindi per prima cosa creiamo un nostro dispositivo “comune” che chiamiamo SER, quindi il codice diventa:

SER.begin(9600);
while (!SER) {}
SER.println(“STARTING READER…. “);

Ora però dobbiamo dire al compilatore di sostituire SER con Serial su Arduino UNO e con SerialUSB su M0.

#if defined(ARDUINO_ARCH_AVR)
   #define SER Serial
#elif defined(ARDUINO_ARCH_SAMD)
   #define SER SerialUSB
#else
   #define SER Serial
#endif

Dovrebbe essere abbastanza intuitivo. Nella prima riga dice al compilatore “se è definita l’architettura ARDUINO_ARCH_AVR”….dove con AVR sappiamo indicare la classica famiglia di microcontrollori di Arduino UNO. In quel caso, riga sottostante, definisci SER con il contenuto Serial (azzurro), ossia, durante tutto il listato, ogni volta che incontri SER, sostituiscilo con Serial. La riga sotto ancora dice “se invece è definita l’architettura ARDUINO_ARCH_SAMD…. e poi …. sostituisci SER con SerialUSB (verde). Per ultimo c’è un #else che dice “in tutti gli altri eventuali casi”, sostituisci SER con Serial (rosa).

Tutto molto semplice. Se vi chiedete “ma dove le trovo le “architetture” che hai scritto qui sopra? Beh, basta che impostate l’output “esteso” del compilatore e fra le prime righe di comando le trovate scritte per cui in base alla scheda su cui state compilando potete andare a valutarle di volta in volta. La parte difficile è prevedere tutte le possibilità, ci saranno sicuramente schede che non conoscete e che si comportano in modo diverso per cui a priori è impossibile creare una fase di “precompilazione” che si adatti a tutto l’hardware esistente eliminando del tutto le possibilità di errore. Diciamo che più architetture conoscete e più precisi potete essere nella precompilazione. Anzi, vi dirò di più, è possibile, nel contesto di una specifica architettura, avere delle sottocategorie di schede con comportamenti diversi che potete intercettare utilizzando parametri addizionali.

Ora c’è solo un ostacolo che ci impedisce di utilizzare un singolo sketch identico in tutte le occasioni, infatti Arduino non è in grado di capire autonomamente se abbiamo collegato un sensore unidirezionale o bidirezionale. Non che sia impossibile da farsi, ma ci complicherebbe notevolmente la vita per cui ho scelto anche in questo caso la compilazione condizionale. Ho messo all’inizio dello sketch la riga #define sensor_bi che se lasciata così com’è viene compilato lo sketch per usare sensori bidirezionali, se invece viene commentata o tolta sarà compilato uno sketch per sensori monodirezionali. Ovviamente poi il listato si “aggiusta” automaticamente in base alla scheda su cui viene compilato.

Ci sono poi degli aggiustamenti da fare, per esempio ho notato che la lettura di Arduino M0 non è così perfetta. Ad esempio la tensione di mezzo che è di 1.651, misurata con un multimetro preciso, viene letta da M0 oscillante fra 1.66 e 1.67V, cosa che comporterà un certo errore nella lettura di piccole correnti. Allo stesso modo dobbiamo ricordarci che nei sensori unidirezionali la tensione letta contiene un “rumore” di base di VCC/2.

Vediamo lo sketch completo:

#include <Ss_McMajan_Config.h>

#define sensor_bi

#ifdef ARDUINO_ARCH_AVR
int step=1024;
float basecalib=0.0189;
float midcalib=0.0098;
#define SER Serial
#else
int step=4096;
#define SER SerialUSB
float midcalib=-0.2; //0.02 è l’errore di lettura del MIO Arduino M0
float basecalib=-0.01970;
#endif

#if defined( ARDUINO_ARCH_AVR ) && defined ( sensor_bi)
float sens=13.3;
#endif
#if defined( ARDUINO_ARCH_AVR ) && !defined ( sensor_bi)
float sens=40
#endif

#if !defined( ARDUINO_ARCH_AVR ) && defined ( sensor_bi)
float sens=8.6;
#endif
#if !defined( ARDUINO_ARCH_AVR ) && !defined ( sensor_bi)
float sens=25.6;
#endif

float adc_step_voltage=(float)Mc_ArduinoVoltageRange/step;
float mid_voltage=(float)Mc_ArduinoVoltageRange/2;
int raw;

void setup()
{
#ifndef ARDUINO_ARCH_AVR
analogReadResolution(12);
#endif
SER.begin(9600);
while (!SER) {} // wait for serial port to connect. Needed for Leonardo only
SER.println(“STARTING READER…. “);
SER.print(“Ampiezza V: “);
SER.println(Mc_ArduinoVoltageRange);
SER.print(“Steps: “);
SER.println(step);
SER.print(“mid_voltage: “);
SER.println(mid_voltage);
SER.print(“adc_step_voltage: “);
SER.print(adc_step_voltage*1000,5);
SER.println(” mV”);
}

void loop()
{
raw = AnalogAvg(A0,500);

float voltage=adc_step_voltage*raw;
#ifdef sensor_bi
float deltavoltage=(voltage-mid_voltage)+midcalib;
#else
float deltavoltage=(voltage-(float)Mc_ArduinoVoltageRange*0.12)+basecalib;
#endif
float corrente=deltavoltage*1000/sens;

SER.print(“Lettura raw = “);
SER.println(raw);

SER.print(“Voltaggio letto: “);
SER.print(voltage,3);
SER.println(” V”);

SER.print(“Voltaggio assoluto: “);
SER.print(deltavoltage,4);
SER.println(” V”);

SER.print(“Corrente assorbita: “);
SER.print(corrente);
SER.println(” A”);

delay(1000);
}

float AnalogAvg(int localpin,uint16_t campioni)
{
float valore=analogRead(localpin);
for(int i=0;i<campioni;i++) valore=(valore+analogRead(localpin))/2;
return(valore);
}

Vi ho evidenziato con dei colori alcune parti del listato. In rosa potete vedere le linee che determinano la compilazione condizionale. In verde quelle che vengono compilate solo sull’M0 e in azzurro quelle che vengono compilate su Arduino UNO . Il listato in se è banale, alla fine dei conti si tratta di leggere un valore analogico ed interpretarlo come abbiamo fatto più sopra nell’articolo. Faccio notare che ho inserito dei fattori di calibrazione diversi a seconda del tipo di sensore e del tipo di Arduino, questi valori sono stati calibrati con il sensore “a vuoto”, ossia con uno scorrimento di corrente nulla, in maniera che l’Arduino utilizzato di volta in volta leggesse un carico di 0A. A tal proposito faccio presente che M0, come detto, a fronte di una maggior precisione ha un maggior rumore di fondo per cui sarebbe opportuno inserire un filtro software per i bassi valori di corrente per impedire letture anomale. Per “limitare i danni”, anzichè fare singole letture, ho creato la funzione AnalogAvg che ho usato per fare la media di 500 campioni. Non è certo una funzione perfetta in quanto non esclude i picchi in eccesso e difetto che rovinano poi la media, avrei potuto usare i filtri di Kalmann presenti nella mia libreria o usare la mediana dei campionamenti, ma non volevo rendere troppo complesso  lo sketch, poi avremmo perso di vista l’obiettivo base di questo articolo, ossia quello di scrivere un unico sketch per sensori e schede di lettura con caratteristiche differenti.

Ora vi lascio al solito video conclusivo, nulla di speciale visto che ho già scritto tutto, ma potete vedere i sensori all’opera durante il funzionamento sia “a vuoto” che con un carico di 5A. Nelvideo ho mostrato solo Arduino UNO e lo sketch è leggermente diverso da quello qui sopra.  Come sempre vi invito ad iscrivervi al mio canale youtube se non l’avete ancora fatto e quando vi arriveranno anche i miei video di cuicina ricordate che prima o poi dovete pur mangiare anche voi 🙂

 

 

 

  2 Responses to “Misurare elevate correnti in tensione continua – it”

  1.  

    ciao, anchio sto usando il tuco stesso sensore ,
    per controllare la carica e scarica del mio impianto sul camper ,
    il mio impianto e composto da 3 pannelli 300 w a 38v 3 regolatori tracer 3210,
    400 AH DI AGM , e sto provando a visuallizare su display 2004 e sul cellulare tramite bylnk

    le tensioni dei 3 pannelli della produzione di ogni singolo regolatore solare e tramite il sensore che stai usando anche tu la carica scarica della batteria penso di arrivare a caricare anche 70ah in estate ,

    con il sensore come ti ci trovi ?

    •  

      Il sensore sinora l’ho testato solo per scrivere l’articolo in previsione di creare il mio sistema di monitoraggio dell’impianto ma devo dire che funzioanva proprio bene. Proprio oggi ho concluso la fase di lettura della tensione di rete (ho avuto dei problemi imprevisti), devo aggiungere le pinze amperometricheper alcune misure non invasive di correnti alternate e poi installerò questi sensori sull’impianto. A questo punto potò finalmente dedicarmi alla programmazione del tutto. La gestione dei dati in rete poi averrà con un sistema che stò costruendo io, è un anno e mezzo che ci lavoro, è pronta tutta la parte che permette la registrazione degli utenti, gestione dei permessi, programmazione di plugin, widget, filtri, scrittura di pagine web, etc. Diciamo che lo scheletro c’è, ma manca ancora qualcosa….posso usarlo per i miei esperimenti ma non per renderlo pubblico…..non ancora…..