Programmazione remota di un multimetro Siglent SCPI da banco usando Python

English version of this post

Per festeggiare il nuovo anno ho deciso che dovevo dotarmi di un multimetro da banco, e dato il mio budget, dopo un po’ di ricerca in rete ho optato per un Siglent SDM3065X.
Ho scelto la versione da 6 1/2 cifre per l’accuratezza molto superiore rispetto ai fratelli minori della stessa linea di prodotto, rispettivamente da 5 1/2 e 4 1/2 cifre. Questo dovrebbe garantirmi, oltre all’accuratezza migliore, anche una altrettanto minor deriva dei parametri di calibrazione nel tempo.

Molte delle caratteristiche, dei pregi e dei difetti dei multimetri da banco SDM3065X/55X/45X sono già stati abbondantemente trattati in svariati video di Youtube. Non intendo quindi fare una review copia della copia della copia di altre, mi limito a dire che finora sono contento della spesa fatta e la rifarei.

Tra i vantaggi noti e pubblicizzati dei multimetri da banco rispetto a quelli portatili, tra cui l’accuratezza, le dimensioni e la luminosità del display, il fatto che sono sempre disponibili sul tuo banco ed essendo alimentati a rete elettrica non hanno mai la batteria scarica, etc etc.. c’è una funzione che viene sì citata ma non sembra andare molto di moda, eppure è molto importante ed utile: la programmazione remota. Forse perché è meno immediata da mostrare e dunque i vari influencer non trovano pratico mostrarla…

La programmazione remota permette di definire sul proprio computer degli algoritmi, o procedure, o sequenze di test, che usano le misure rilevate dagli strumenti collegati e fanno potenzialmente qualunque cosa (tra cui ad esempio la registrazione dei dati per una successiva consultazione e statistiche). Se nel banco di lavoro ci sono anche alimentatori e carichi programmabili da remoto, diventa possibile usarli in modo combinato, aprendo a un mondo di scenari di test automatizzati.

L’SDM3065X, una volta connesso alla LAN via ethernet, espone un servizio SCPI (documentato qui) e utilizzabile da qualunque applicazione client via TCP/IP. L’accesso è possibile anche via USB, ma personalmente lo trovo meno pratico rispetto alla connesione di rete.

Per utilizzare il servizio basta connettersi via TCP all’indirizzo IP esposto dal DMM e iniziare ad inviare comandi e ricevere le letture. Ma ci sono librerie per i vari linguaggi di programmazione che rendono l’accesso molto più facile. La libreria di riferimento per connettersi ad un multimetro digitale è la “NI Visa” della National Instruments; nel mio caso ho potuto evitare di installarla perché ho usato Python e due librerie pyvisa + pyvisa-py, quest’ultima svolge il ruolo di NI Visa ed è di fatto un sostituto open source.

Scrivo questo post perché ci ho messo veramente poco a far funzionare il sistema: sia il collegamento remoto col multimetro, sia il salvataggio dei dati di misurazione in un database SQLite con successiva analisi, e ho pensato che un piccolo tutorial potrebbe aiutare molti ad accedere a questa funzionalità.

Perché e quando usare la programmazione remota?

Chi lo fa per lavoro sa già tutto, per un hobbista la domanda non è banale. Immaginiamo questi esempi:

  1. Abbiamo costruito un alimentatore chiudendo un modulo in una scatola di plastica (magari corredandola di amperometro, voltmetro, ecc) e siamo quasi sicuri che la dissipazione di calore non sarà un problema. Ma prima di consegnarlo al nostro amico che ce l’ha chiesto, dormiremmo meglio la notte se potessimo verificare le nostre ipotesi.
  2. Un alimentatore è difettoso e abbiamo bisogno di tenerlo acceso per molto tempo, facendo misurazioni ripetute, per riprodurre il problema.
  3. Abbiamo appena costruito un circuito amplificatore audio e ci piacerebbe verificare che possa reggere il carico per cui l’abbiamo progettato, con un duty-cycle del 100% (ovvero tenendo il carico sempre collegato alla potenza nominale).
  4. La nostra rete elettrica ha dei cali o dei picchi di tensione e ci piacerebbe sapere cosa succede la notte.

Sono solo dei banali esempi ma in tutti questi casi abbiamo bisogno di fare misure ripetute per un tempo anche molto lungo, in modo affidabile e in nostra assenza, per poi analizzare i risultati e trarre le nostre conclusioni. Capite bene che un multimetro da solo, anche se con il suo bravo display e la sua memoria locale, finisce presto la sua utilità. Il nostro computer invece sarebbe perfetto. Poterlo usare ci dà la possibilità di accedere a questo tipo molto importante di test in cui di fatto misuriamo dei parametri di qualità di un componente/circuito/apparato che stiamo costruendo o riparando.

Esempio di risultati che si possono ottenere

Volevo misurare la stabilità della tensione d’uscita di un mio alimentatore da banco basato su LM317:

Prima ora di logging delle letture:

Fin qui tutto bene, ma se lo guardiamo in un tempo più ampio includendo la notte:

Possiamo quindi dire che abbiamo avuto una deriva nella tensione d’uscita dopo qualche ora. Tale effetto è dovuto a molteplici cause, tra le più rilevanti ci sono sicuramente l’andamento della temperatura ambiente (che impatta non solo sul dispositivo sotto test ma anche, in misura inferiore, sul multimetro!), manopole e potenziometri, parametri dell’integrato LM317, …

Osservando l’entità della deriva la variazione totale di tensione è di circa 6 mV in 12 ore, trascurabile nella gran parte dei casi, ma… sarei stato mai capace di rilevarla e misurarla con facilità senza questa funzione? Comunque ora so che quel mio alimentatore deriva di 12 mV / giorno, un dato che potrebbe servirmi in qualche prossimo lavoro che farò.

Altro esempio:

Variazione di temperatura interna in un alimentatore tra stao ON e OFF, Iout=1A.
Notare che la temperatura Toff= Tambiente

che mostra l’escursione termica tra gli stati OFF e ON in un alimentatore avente Vout=5V e Iout = 1A. Per la misura ho usato una banalissima termocoppia tipo K.

Impostazione dell’ambiente di programmazione

Per dotarvi del mio stesso ambiente di programmazione dovrete installare i seguenti tool:

  • PyCharm CE, una IDE Python molto famosa e completa (forse su Windows bisogna installare prima Python)
  • DB Browser for SQLite, un tool grafico per aprire e lavorare con i file database SQLite
    • include anche dei semplici grafici, tipo quelli che vedete qui sopra
    • Ha l’export verso CSV
    • e molte altre utili funzioni

Il mio ambiente è su Apple M1, Macbook Air. Alcuni dettagli della procedura potrebbero variare leggermente sotto altri OS.

Ora, per prima cosa connettete il vostro multimetro alla rete. Impostate il TCP/IP in modo da aggiungerlo alla vostra LAN. Supponendo che stiate utilizzando DHCP, controllate che gli venga assegnato un indirizzo IP nella sottorete giusta (o nel pannello di controllo del multimetro, o nella pagina dei “DHCP lease” del vostro router). No indirizzo IP -> no collegamento al multimetro, perciò vi consiglio caldamente di smarcare subito questo punto!

Impostazione del progetto in Pycharm

Creiamo ora un nuovo progetto in PyCharm. Dopo averlo aperto, andate sul menu “File-> New Project…”, si aprirà un popup simile a questo:

dove suggerirei di selezionare “New Virtualenv environment” come si vede nella schermata. Questo farà si che le librerie e pacchetti scaricati da questo progetto rimangano locali alla cartella del progetto, rendendo anche un po’ più stabile l’ambiente Python.
Impostare la cartella voluta nel campo Location sopra mostrato. Una volta fatto cliccate sul pulsante “Create” in basso a destra e si dovrebbe aprire il workspace del nuovo progetto.

Il nostro programma Python userà pyvisa (https://pyvisa.readthedocs.io/en/latest/index.html) e pyvisa-py (quest’ultimo rimpiazza NI-Visa che quindi non dovremo preoccuparci di scaricare ed installare).

Per installarle cliccare i selettore “Python Packages” in basso e ricercare pyvisa e successivamente pyvisa-py:

e per ciascuna di esse cliccare il tasto “Install” che compare sul lato destro della pagina descrittiva.

Installare con questa procedura i seguenti pacchetti: pyvisa, pyvisa-py, psutil e zeroconf.

Una volta fatto siete pronti per collegarvi al multimetro.

Connessione remota al multimetro

Innanzitutto provate questo:

import pyvisa

rm = pyvisa.ResourceManager('@py') # '@py' dice a pyvisa di usare pyvisa-py
resources = rm.list_resources()
print(resources)

Dovrebbe produrre un output di questo tipo:

('TCPIP::192.168.1.232::INSTR',)

se si, il nostro multimetro è stato trovato! Nel caso avessimo più di un dispositivo connesso, la tupla visualizzata conterrebbe altrettante stringhe, e sarebbe nella forma (stringa1, stringa2,…stringaN,).

Connettiamoci ora al multimetro e facciamci restituire il suo IDN (ovvero il suo identificativo):

for resource in resources:
    instrument = rm.open_resource(resource) # Connessione al DMM, restituisce un oggetto che lo rappresenta
    instrument_id = instrument.query('*IDN?').strip() 
    print(instrument_id)

Se abbiamo solo un multimetro non abbiamo realmente bisogno di un ciclo for, ma concentriamoci dapprima sul codice ivi contenuto.

Ciascuna resource è una stringa, es. ‘TCPIP::192.168.1.232::INSTR’.

Invocando rm.open_resource(resource) ci stiamo connettendo al multimetro, ottenendo un oggetto che lo rappresenta, e lo salviamo nella variabile instrument.

Invocando instrument.query(‘*IDN?’) stiamo chiedendo al nostro strumento di restituire il suo identificativo IDN.

Il valore stampato da print sarà qualcosa tipo questa se ci stiamo connettendo ad un DMM della Siglent:

Siglent Technologies,SDM3065X,<il seriale del DMM>,3.01.01.10

che è appunto una stringa univoca.

In generale, la LAN potrebbe avere più di uno strumento installato, anche se oggi magari non è così.

Quasi certamente comunque, gli strumenti verrebbero configurati con DHCP e non sarà una buona idea usare la risorsa di rete (es. ‘TCPIP::192.168.1.232::INSTR’) come elemento costante per connettersi. Molto meglio usare l’IDN che è stato creato apposta per questo.

Ecco quindi che il ciclo for mostrato prima inizierà ad avere una sua utilità:

import pyvisa

rm = pyvisa.ResourceManager('@py') # '@py' dice a pyvisa di usare pyvisa-py
resources = rm.list_resources()
multimeter1 = None # qui assegneremo l'oggetto "instrument" relativo al nostro multimetro
for resource in resources:
    instrument = rm.open_resource(resource) # Connessione al DMM, restituisce un oggetto che lo rappresenta
    instrument_id = instrument.query('*IDN?').strip() 
    if instrument_id == 'Siglent Technologies,SDM3065X,<il seriale del DMM>,3.01.01.10':
        print('Using multimeter 1: ' + instrument_id)
        multimeter1 = instrument

# my test code starts here...

infatti ci permette di trovare il nostro DMM mediante il suo ID univoco e assegnarlo alla variabile multimeter1. Il ciclo for diventerà addirittura necessario quando avremo più strumenti e vorremo identificarli con certezza per stabilire quale di questi è il nostro multimetro A e quale è il multimetro B.

Inviare richieste di letture

Chiediamo ora al nostro multimetro di misurare una tensione DC con auto range. basta una singola riga di codice!

voltage_string = multimeter1.query('MEAS:VOLT:DC? AUTO').strip()

e restituirà una stringa tipo questa:

+5.09841574E+00

ed ecco qui la nostra misura di 5V DC! Notare che abbiamo dovuto aggiungere “.strip()” al valore restituito da query() perché questo contiene dei caratteri vuoti (ritorni a capo) alla fine del valore e la cosa potrebbe dare problemi nella successiva elaborazione.

Salvataggio dei dati nel database

Fin qui tutto bene: ci siamo connessi al nostro DMM e abbiamo ottenuto le letture che ci interessavano. Ora dobbiamo salvarle in un database.

Questa parte è stata anch’essa molto facile e si compone di due parti: inizializzazione del database, scrittura di dati nel database.

Sqlite3 è un db su file, molto leggero da utilizzare e usatissimo. Inizializziamo il database con una tabella per salvare le nostre misure:

import sqlite3
dbconn = sqlite3.connect('my_measurements.db')
dbconn.execute('''CREATE TABLE IF NOT EXISTS MEASURES (id INTEGER PRIMARY KEY AUTOINCREMENT, meas_time 
TIMESTAMP NOT NULL, command TEXT NOT NULL, value TEXT NOT NULL)''')
dbconn.commit()

che crea (se non già presente) un file “my_measurements.db” contenente il database, nella cartella del progetto. Nel database verrà creata la tabella “MEASURES”, che conterrà un campo id autoincrementante, un campo timestamp (ovvero data-ora-minuti-secondi) meas_time, e il nostro valore value definito come testo. Tutti i campi sono definiti come not null, quindi saranno obbligatori.

Per salvare le misurazioni nel database, aggiungere infine un codice tipo questo, che continuerà a misurare e salvare i dati fino a che non lo interrompiamo:

import datetime
import time

while True:
    command = 'MEAS:VOLT:DC? AUTO'
    val_string = self.multimeter1.query(command).strip()
    value = float(val_string)
    now = datetime.datetime.now()
    dbconn.execute('INSERT INTO MEASURES (meas_time,command,value) VALUES (?,?,?)',
                   (now, command, value))
    print'Inserted measured value: ' + command + ', ' + str(value))
    dbconn.commit()
    time.sleep(5)

… ed è finito, anche se il tutto è di livello molto “base”!

Per fermare il programma premere il bottone di “stop” quadrato rosso nel pannello “run” di PyCharm oppure cliccare nella voce di menu Run -> Stop ‘main’.

Visualizzare i dati

E’ arrivato finalmente il momento di visualizzare i risultati della nostra sessione, apriamo quindi il programma DB Browser for SQLite.

Clicchiamo su “Apri Database” e selezioniamo il database del nostro progetto. Possiamo fare questo anche mentre il nostro progamma python sta scrivendo i dati. L’importante in questo caso è non modificare il database.

Si aprirà il file sulla visualizzazione “Struttura database”: cliccare ora su “Naviga nei dati” e selezionare la tabella MEASURES. Abbiamo finito! Il pannello sarà tipo questo:

Si può ordinare per campo id in modo discendente, in questo modo possiamo vedere i dati popolarsi cliccando sul pulsante di refresh vicino al selettore di tabella. Il pannello a destra invece permette di fare il grafico dei dati, selezionando meas_time come variabile X e value come variabile Y1:

Grafico dei record selezionati nel pannello di sinistra.

Si possono filtrare i record della tabella MEASURES, nel qual caso il grafico si aggiornerà automaticamente di conseguenza. Si possono salvare i dati su file CSV per poi aprirlo con Excel/Libreoffice e fare ulteriori analisi.

Punti di attenzione / sviluppi futuri

VISA Timeouts

Potrebbe succedervi di avere dei timeout interrogando il multimetro/i. Per fare sì che il programma non si fermi e che invece continui nel suo loop infinito di misurazioni e inserimenti dati, proteggiamo il codice racchiudendolo in una clausola try..except, ad esempio in questo modo:

command = 'MEAS:VOLT:DC? AUTO'
while True:
    try:
        val_string = self.multimeter1.query(command).strip()
        value = float(val_string)
        now = datetime.datetime.now()
        dbconn.execute('INSERT INTO MEASURES (meas_time,command,value) VALUES (?,?,?)',
                       (now, command, value))
        print('Inserito nel database il record ' + command + ', ' + str(value))
        dbconn.commit()
        time.sleep(5)
    except pyvisa.errors.VisaIOError as v_e
        print(v_e)

In caso di errore si avrà evidenza nella console grazie all’istruzione print(v_e) ma il programma continuerà ad interrogare il DMM e salvare dati.

Comandi multiriga

Potreste avere bisogno di mandare comandi multiriga al vostro DMM, o comunque fare interazioni più complesse di un semplice ‘MEAS:VOLT:DC? AUTO’.

La documentazione di programmazione infatti riporta moltissimi casi di comunicazione multiriga per ottenere un dato.

Per farlo, basti notare che l’oggetto instrument non ha solo il metodo query() ma anche write(). Esempio:

command = 'CONF:VOLT:DC ' + scale
multimeter1.write(command)
command = 'SAMP:COUN 1'
multimeter1.write(command)
while True:
    # Più veloce rispetto a 'MEAS' in quanto non riconfiguro niente tra una lettura e l'altra:
    command = 'READ?'
    val_string = multimeter1.query(command).strip()
    value = float(val_string)
    ....

Conclusion

Questo post è un po’ più lungo di quanto avessi voluto ma spero serva ad altri per introdursi nella programmazione di un multimetro digitale compatibile coi comandi di rete SCPI. Spero vi permetta di impostare una sessione di test automatizzata anche se non siete dei professionisti di programmazione, e che possiate ottenere il massimo dal vostro DMM e dai vostri progetti!

Realizzazione di circuiti “Manhattan style”

Oggi voglio condividere una tecnica di costruzione di prototipi di circuito elettronico chiamata “Manhattan style”.

Mi ha colpito perché riesce ad unire la semplicità di realizzazione (un circuito è fattibile con pochissimi mezzi) alla possibilità di realizzare circuiti che lavorano in alta frequenza / radiofrequenza, o circuiti a larga banda, quindi ad esempio applicazioni radio, fino alle VHF e oltre. Inoltre, per costruzione, un circuito così realizzato ha piste di lunghezza minima, permettendo l’erogazione di una discreta potenza.

In rete c’è una certa quantità di documentazione in merito.

Segnalo subito gli ottimi articoli di Chuck Adams K7QO:

e il video che forse per primo mi ha avvicinato a questa tecnica, di W2AEW: #122: Electronic Circuit Construction Techniques: review of some prototype circuit building methods, che passa in rassegna vari metodi di costruzione di prototipi.

Se capite l’inglese, potete tranquillamente saltare il resto di questo articolo e navigare partendo dai link sopra.

Il “Manhattan style”.

Concettualmente è molto semplice. Si parte da una basetta per circuiti stampati vergine a faccia singola e da dei frammenti di basetta a faccia singola di area piccola che chiamiamo “zolle”, ottenuti ad esempio con una roditrice, una tenaglia o una tagliatrice.

Dato lo schema elettrico, ciascun nodo della rete elettrica corrisponde ad una “zolla”. Supponiamo di voler fare un partitore resistivo, come illustrato qui:

 

Partitore resistivo con i nodi evidenziati e cerchiati in rosso.

Come si vede, si identifica con una lettera ciascun nodo della rete elettrica, che corrisponderà ad una zolla Manhattan. Da qui alla realizzazione non serve usare alcun CAD, bastano solo il cervello e un po’ di buona volontà.

La basetta e le zolle tagliate con una tenaglia da lamiera.

Posizionare le zolle nella basetta e incollarle secondo la logica dello schema elettrico. Nei riferimenti si dice di usare una “super glue”, io preferisco la colla a caldo perché con il semplice posizionamento del saldatore si fonde nuovamente e diventa riposizionabile. Il raffreddamento è immediato grazie al rame.

 

Mettere una goccia di colla fusa sulla zolla e attaccarla alla basetta.

 

Basetta con le zolle incollate. La superficie di base sarà per noi un ottimo piano di massa!

 

Ora, procediamo con la saldatura delle nostre resistenze di partitore. Il saldatore dovrà avere una discreta riserva di potenza, credo che 40W siano sufficienti nella gran parte dei casi. Sagomiamo le resistenze nel seguente modo:

 

…e procediamo con la saldatura. Si inizia stagnando la zolla e successivamente i componenti:

 

 

Schema elettrico implementato, corredato di scritte a penna indelebile. Il layout dei componenti riflette fedelmente lo schema elettrico ed è facile da interpretare e seguire!

Nello spazio libero disponibile sul piano di massa si possono aggiungere, con una penna indelebile, informazioni utili come ad esempio la lettera della zolla, il numero di componente, note, ecc…

In presenza di circuiti integrati?

Nel caso di circuiti integrati si possono sagomare zolle più complesse, aiutandosi con appositi strumenti da taglio.

Ad esempio è facile realizzare una zolla per ospitare uno zoccolo per IC con pedinatura DIP:

Base per socket DIP8 realizzata tagliando lo spezzone di basetta con un trapano ad alta velocità Proxxon.

Una simile zolla va sempre incollata sulla basetta ospitante, mentre si possono saldare i collegamenti ai pin dell’integrato nelle “isole” di rame scavate su di essa, come si vede nella foto. Con un trapano ad alta velocità e un minidisco da taglio per metalli si ottiene facilmente questo risultato, asportando solo lo strato di rame della basetta. La distanza tra le “isole” visibile in foto è certamente sufficiente per operare con tensioni fino all’ordine dei 100V.

Una tecnica alternativa per gli IC: la “Dead Bug Technique”, ovvero la tecnica dello scarafaggio morto.

Potrebbe risultare difficoltoso ricavare una zolla per il montaggio di uno zoccolo per IC. In questo caso, possiamo sempre ricorrere ad un metodo ancora più semplice, che va sotto il nome di “dead bug technique”.

Come suggerisce il nome, si tratta di posizionare e incollare il chip “capovolto”, sulla basetta, ricordandosi che la pedinatura ora risulterà specularmente invertita!

Il risultato non è elegante da vedere ma funziona, ed è duro da battere se c’è bisogno di sfruttare al massimo la banda passante del componente.

Il difetto maggiore della tecnica “Dead bug” che ho riscontrato è la relativa debolezza dei pin dell’integrato, per cui bisogna stare molto attenti quando si opera su di essi. Non è facile saldare componenti direttamente sui piedini, ma con l’esperienza il problema scompare. Un altro difetto è la scarsa manutenibilità della parte di circuito così realizzata. La zolla con il socket è un’alternativa decisamente migliore da questo punto di vista.

 

Vantaggi dell’approccio Manhattan.

L’approccio è molto semplice e diretto, e ha l’enorme pregio di mantenere facile lo sbroglio del circuito e vicini i componenti tra loro.

Inoltre, se non si devono gestire frequenze altissime (VHF), è possibile disporre i componenti discreti lasciando ampio spazio per applicare la sonda di un oscilloscopio ed avere anche un circuito facilissimo da debuggare.

Ultimo ma non ultimo, no necessità di CAD o altri sistemi, no sostanze chimiche, nulla: solo una basetta e degli utensili da taglio.

 

73 de IU3JSX Marco