Retrofitting degli strumenti di laboratorio con capacità IoT tramite l'Intelligenza Artificiale Generativa

Ari Mahpour
|  Creato: aprile 4, 2024  |  Aggiornato: luglio 1, 2024
Riqualificazione degli strumenti di laboratorio con capacità IoT tramite l'Intelligenza Artificiale Generativa

Nell'articolo Retrofitting your Old Power Supply to be Smartphone Controllable abbiamo dato nuova vita a un vecchio alimentatore dotandolo di capacità IoT. In questo articolo esamineremo un modo più efficiente per dotare tutti i tuoi strumenti di laboratorio di capacità IoT (specificamente quelli controllati tramite VISA). Invece di costruirlo da zero, sfrutteremo l'AI Generativa per svolgere la maggior parte del lavoro pesante. Seguendo questo tutorial dovresti essere in grado di applicare questi concetti per creare driver abilitati al web per tutti i tuoi strumenti di laboratorio e accelerare anche il tuo sviluppo generale.

Punto di partenza

In questo articolo ci concentreremo sulla realizzazione del servizio web che funge da intermediario tra lo strumento stesso e Internet. Di seguito è illustrata la connessione end-to-end tra lo strumento e internet (ovvero l'accesso tramite sito web).

Diagramma a blocchi

Figura 1: Comunicazione end-to-end tra lo strumento e Internet

Prima di fare ciò, è importante stabilire che non è completamente necessario scrivere tutti i driver degli strumenti da soli. Possiamo sfruttare ciò che è già stato fatto online dai produttori o possiamo utilizzare repository open source. Per brevità, utilizzerò ciò che ho già trovato online ma userò l'AI Generativa per mettere insieme un framework che mi soddisfi.

Sto utilizzando l'alimentatore DP832 e il carico elettronico DL3021 di Rigol. Dopo una rapida ricerca su GitHub, ho trovato librerie Python per l'alimentatore DP832 che contengono tutti i comandi SCPI necessari per iniziare. Un approccio alternativo sarebbe prendere un elenco di comandi SCPI dal manuale del DP832, consegnarlo a un modello di linguaggio avanzato (LLM), per esempio ChatGPT o Gemini, e far generare a lui le funzioni. Sono un po' esigente quindi definirò il mio processo di configurazione PyVISA e poi sfrutterò la maggior parte di ciò che è già stato fatto. Ecco il mio processo di configurazione PyVISA generico (incapsulato in una classe separata): 

class CommBase:

   USBConnType = Literal["USBTMC", "VISA", "Socket"]

    def __init__(self, usb_conn_type: USBConnType, vid: int = None, pid: int = None, visa_resource_prefix: str = None):

        self.visa_resource_prefix = visa_resource_prefix

        self.usb_conn_type = usb_conn_type

        if usb_conn_type == "USBTMC":

            self.configure_usbtmc(vid, pid)

        elif usb_conn_type == "VISA":

``` self.configure_visa(vid, pid) ``` ``` elif usb_conn_type == "Socket": ``` ``` pass ``` ``` else: ``` ``` raise ValueError(f"Tipo di connessione USB non valido: {usb_conn_type}. I tipi validi sono {self.VALID_USB_CONN_TYPES}") ``` ``` ``` ``` def configure_usbtmc(self, vid: int, pid: int): ``` ``` self.inst = usbtmc.Instrument(vid, pid) ``` ``` ``` ``` def configure_visa(self, vid: int, pid: int): ``` ``` self.rm = pyvisa.ResourceManager() ``` ``` instrument_list = self.rm.list_resources() ``` ``` visa_address = self.find_visa_resource(vid, pid, instrument_list, prefix=self.visa_resource_prefix) ``` ``` if visa_address is not None: ``` ``` self.inst = self.rm.open_resource(visa_address, read_termination="\n") ``` ``` else: ``` ``` raise IOError(f'Nessun dispositivo VISA trovato usando vid "{vid}" e pid "{pid}" ma sono stati trovati i seguenti dispositivi VISA: {instrument_list}') ``` ``` ``` ``` @staticmethod ``` ``` def find_visa_resource(vid: int, pid: int, resource_strings: list, prefix: str) -> str: ``` ``` hex_vid, hex_pid = f"0x{vid:X}", f"0x{pid:X}" ``` ``` dec_vid, dec_pid = str(vid), str(pid) ``` ``` for resource in resource_strings: ``` ``` parts = resource.split("::") ``` ``` if len(parts) >= 4: ``` ``` serial_and_more = parts[3] ``` ``` if (any(x in resource for x in (hex_vid, dec_vid)) and any(x in resource for x in (hex_pid, dec_pid)) and serial_and_more.startswith(prefix)): ``` ``` return resource ``` ``` return None ``` ``` def query_device(self, command: str) -> str: ``` ``` if self.usb_conn_type == "USBTMC": ``` ``` return self.inst.ask(command) ``` ``` elif self.usb_conn_type == "VISA": ``` ``` return self.inst.query(command) ``` ``` else: ``` ``` raise NotImplementedError(f"Il metodo di query per {self.usb_conn_type} non è stato trovato.") ``` ``` def write_device(self, command: str): ``` ``` self.inst.write(command) ``` ``` def close(self): ``` ``` self.inst.close() ``` ``` if self.usb_conn_type == "VISA": ``` ``` self.rm.close() ``` ``` def id(self) -> dict: ``` ``` id_str = self.query_device("*IDN?").strip().split(",") ``` ``` return { ``` ``` "manufacturer": id_str[0], ``` ``` "model": id_str[1], ``` ``` "serial_number": id_str[2], ``` ``` "version": id_str[3], ``` ``` } ```

Ho rimosso tutti i commenti, gli spazi extra e anche alcune sequenze di configurazione (come il logging) per brevità. Come puoi vedere, ho alcune funzioni generiche più il supporto sia per PyVISA che per USBTMC. La maggior parte delle librerie Python basate su SCPI che trovi online non avrà questa funzionalità di base. Questo va bene perché posso estendere questa classe nella mia nuova classe:

 

from base.CommBase import CommBase

class DP(CommBase):

    def channel_check(self, channel):

        assert NotImplementedError

 

    def get_output_mode(self, channel: int) -> str:

        self.channel_check(channel)

        return self.query_device(f":OUTP:MODE? CH{channel}").strip()

 

    # … Il codice è stato rimosso per brevità

 

    def measure_current(self, channel):

        self.channel_check(channel)

        meas = self.query_device(f":MEAS:CURR? CH{channel}").strip()

        return float(meas)

 

    def measure_voltage(self, channel):

        self.channel_check(channel)

        meas = self.query_device(f":MEAS? CH{channel}").strip()

        return float(meas)

 

    def measure_all(self, channel):

        self.channel_check(channel)

        meas = self.query_device(f":MEAS:ALL? CH{channel}").strip().split(",")

        return {

            "voltage": float(meas[0]),

            "current": float(meas[1]),

```             "potenza": float(meas[2]),         }   class DP712(DP):     def controllo_canale(self, canale):         assert canale in [1, ""], f"Il canale di uscita {canale} non è supportato"   class DP821(DP):     def controllo_canale(self, canale):         assert canale in [1, 2, ""], f"Il canale di uscita {canale} non è supportato"   class DP832(DP):     def controllo_canale(self, canale):         assert canale in [1, 2, 3, ""], f"Il canale di uscita {canale} non è supportato" Ho preso diversi esempi online e li ho passati a ChatGPT. Ho chiesto di:

  1. Convertire il file in una classe
  2. Aggiungere blocchi di commento in stile docstring per ogni funzione
  3. Scrivere test per validare queste funzioni (come una classe separata)

Utilizzare l'IA Generativa per questo compito ha ridotto un lavoro di più ore a 60 secondi. Inoltre, sono stato in grado di validare molto rapidamente i driver che ho trovato online eseguendo i test generati automaticamente da ChatGPT. Ad esempio, ho scoperto molto rapidamente che uno dei comandi SCPI per il DL3021 per impostare la modalità di funzionamento del carico elettronico era effettivamente errato. Osservando i test eseguirsi in tempo reale, ho notato che la modalità non stava cambiando sul mio strumento. Una rapida consultazione del manuale SCPI e sono stato in grado di correggerlo.

Servizio Web

A questo punto abbiamo una buona base per la nostra libreria Python per controllare i nostri strumenti. L'obiettivo ora è posizionare un servizio web davanti alla libreria degli strumenti, dandoci la possibilità di controllarli via web. Supponendo di non sapere nulla sui framework web, posso semplicemente chiedere a ChatGPT (o a qualsiasi LLM) di eseguire l'intera funzione per me. Ecco il prompt che ho usato per iniziare:

Ho bisogno di creare un servizio web che controllerà il mio strumento utilizzando URL di base (tramite un browser web). Non conosco molto sui servizi web o sui framework ma sono familiare con Python. Scrivi il codice Python completo per realizzare questo compito.

Ecco la classe che controlla il mio strumento:

<pre><code>```

{codice di sopra}

```

</code></pre>

E la (risposta parziale):

```

Risposta del prompt di ChatGPT

Figura 2: Risposta dal prompt di ChatGPT

La mia parte preferita riguardo i sofisticati LLM a pagamento è che realmente scompongono il compito per te, ti educano e forniscono una soluzione piuttosto buona come prima iterazione. In Gemini vs. ChatGPT: Chi Scrive Miglior Codice? ho messo a confronto i due LLM e (attenzione spoiler) ho scoperto che l'ultima versione, più avanzata, del Gemini di Google era effettivamente molto buona (se non al pari di ChatGPT 4). Usare uno qualsiasi di questi LLM produrrà un risultato simile a quello mostrato sopra.

Se voglio inserire questo in una classe o riformattarlo posso semplicemente rispondere alla chat e fare la mia richiesta. Vuoi che il tuo codice sia commentato? Nessun problema, basta chiedere!

Prompt: Aggiungi blocchi di commento in stile docstring a ogni funzione. Riscrivi tutta la classe come risultato così posso copiarla e incollarla di nuovo nel mio editor di codice.

Prompt di ChatGPT

Figura 3: Prossima risposta dal prompt di ChatGPT

Test

Ora che abbiamo fatto creare il modulo Python dall'IA Generativa possiamo chiederle di scrivere test per noi o mostrarci come testare manualmente:

URL di Test

Figura 4: URL di test manuale da ChatGPT

Test Automatico

 Figura 5: Test automatico scritto da ChatGPT

Dopo aver eseguito (o modificato ed eseguito) questi test dovremmo essere in grado di validare il nostro nuovo modulo Python che fa da interfaccia tra il web e il nostro strumento. 

Conclusione

In questo articolo abbiamo messo insieme un modulo Python che controllava il nostro strumento sfruttando codice esistente sul web e l'Intelligenza Generativa. Dopo che il nostro LLM ha completato il modulo, abbiamo poi introdotto un nuovo modulo che fungeva da intermediario tra Internet e lo strumento stesso (tramite un servizio web). Abbiamo anche dato un'occhiata rapida a come l'Intelligenza Generativa può guidarci attraverso l'intero processo, includendo test manuali o automatizzati. La parte migliore di questo esercizio è che, se fatto correttamente, avrebbe dovuto richiedervi molto poco tempo per essere assemblato. La prima volta potrebbe richiedere uno sforzo extra ma ripetere questo processo per molti strumenti dovrebbe essere una brezza (e comportare molto poco tempo di sviluppo). È chiaro che l'Intelligenza Generativa ha completamente cambiato il panorama per tutti noi e questo articolo lo dimostra davvero. Speriamo che sarete ispirati a creare il prossimo set di librerie per strumenti sfruttando l'Intelligenza Generativa e a contribuirle alla restante comunità.

Tutto il codice sorgente utilizzato in questo progetto può essere trovato su: https://gitlab.com/ai-examples/instrument-controllables.

Sull'Autore

Sull'Autore

Ari è un ingegnere con una solida esperienza nei campi di progettazione, produzione, collaudo e integrazione di sistemi elettrici, meccanici e software. Ama riunire gli ingegneri addetti alla progettazione, alla verifica e al collaudo e farli lavorare insieme come un'unità affiatata.

Risorse correlate

Documentazione Tecnica Correlata

Tornare alla Pagina Iniziale
Thank you, you are now subscribed to updates.