Modernizando Instrumentos de Laboratório com Capacidades IoT Usando IA Generativa

Ari Mahpour
|  Criada: Abril 4, 2024  |  Atualizada: Julho 1, 2024
Modernizando Instrumentos de Laboratório com Capacidades IoT Usando IA Generativa

Em Adaptando sua Antiga Fonte de Alimentação para ser Controlada por Smartphone, nós demos nova vida a uma antiga fonte de alimentação ao proporcionar-lhe capacidades de IoT. Neste artigo, vamos olhar para uma maneira mais simplificada de trazer capacidades de IoT para todos os seus instrumentos de laboratório (especificamente aqueles controlados usando VISA). Em vez de construir do zero, vamos aproveitar a IA Generativa para fazer a maior parte do trabalho pesado. Após seguir este tutorial, você deverá ser capaz de levar esses conceitos para construir drivers habilitados para a web para todos os seus instrumentos de laboratório e também acelerar o seu desenvolvimento geral.

Base

Neste artigo, vamos focar em montar o serviço web que serve como intermediário entre o instrumento em si e a Internet. A seguir está uma ilustração da conexão de ponta a ponta entre o instrumento e a internet (ou seja, acesso via site).

Diagrama de Blocos

Figura 1: Comunicação de ponta a ponta entre o instrumento e a Internet

Antes de fazer isso, é importante estabelecer que não é completamente necessário escrever todos os drivers dos instrumentos nós mesmos. Podemos aproveitar o que já foi feito online pelos fabricantes ou podemos utilizar repositórios de código aberto. Pela brevidade, vou aproveitar o que já encontrei online, mas usar a IA Generativa para montar uma estrutura com a qual estou satisfeito.

Estou usando a fonte de alimentação DP832 e a carga eletrônica DL3021 da Rigol. Após uma rápida pesquisa no GitHub, encontrei bibliotecas Python para a fonte de alimentação DP832 que contêm todos os comandos SCPI necessários para começar. Uma abordagem alternativa seria pegar uma lista de comandos SCPI do manual do DP832, entregá-la a um modelo de linguagem de grande escala (LLM), por exemplo, ChatGPT ou Gemini, e fazê-lo gerar as funções para mim. Sou um pouco exigente, então vou definir meu próprio processo de configuração PyVISA e depois aproveitar a maior parte do que já foi feito. Aqui está o meu processo de configuração PyVISA genérico (encapsulado em uma classe separada): 

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 de conexão USB inválido: {usb_conn_type}. Os tipos válidos são {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'Nenhum dispositivo VISA encontrado usando vid "{vid}" e pid "{pid}" mas os seguintes dispositivos VISA foram encontrados: {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"Método de consulta para {self.usb_conn_type} não encontrado.") 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 { "fabricante": id_str[0], "modelo": id_str[1], "número_de_série": id_str[2], "versão": id_str[3], } ```

Removi todos os comentários, espaços extras e até algumas sequências de configuração (como registros) para brevidade. Como você pode ver, tenho algumas funções genéricas além de suporte para PyVISA e USBTMC. A maioria das bibliotecas Python baseadas em SCPI que você encontra online não terá essa funcionalidade básica. Isso é bom porque posso estender essa classe para a minha nova 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()

 

    # … Código foi removido para brevidade

 

    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]),

            "potência": float(meas[2]),

        }

 

class DP712(DP):

    def channel_check(self, canal):

        assert canal in [1, ""], f"Canal de saída {canal} não suportado"

 

class DP821(DP):

    def channel_check(self, canal):

        assert canal in [1, 2, ""], f"Canal de saída {canal} não suportado"

 

class DP832(DP):

    def channel_check(self, canal):

        assert canal in [1, 2, 3, ""], f"Canal de saída {canal} não suportado"

Eu peguei alguns exemplos diferentes online e os passei para o ChatGPT. Eu o instruí a:

  1. Converter o arquivo em uma classe
  2. Adicionar blocos de comentários no estilo docstring para cada função
  3. Escrever testes para validar essas funções (como uma classe separada)

Usar a IA Generativa para essa tarefa transformou um trabalho de várias horas em 60 segundos. Eu também consegui, muito rapidamente, validar os drivers que encontrei online executando os testes gerados automaticamente que o ChatGPT escreveu para mim. Por exemplo, descobri, muito rapidamente, que um dos comandos SCPI para o DL3021 para definir o modo de operação da carga eletrônica estava na verdade incorreto. Observando os testes rodarem em tempo real, notei que o modo não estava mudando no meu instrumento. Uma rápida consulta no manual SCPI e eu consegui corrigi-lo.

Serviço Web

Neste ponto, temos uma boa base para nossa biblioteca Python controlar nossos instrumentos. O objetivo agora é colocar um serviço web na frente da biblioteca de instrumentos, nos dando a capacidade de controlá-los pela web. Supondo que eu não saiba nada sobre frameworks web, eu posso simplesmente pedir ao ChatGPT (ou qualquer LLM) para realizar a função inteira para mim. Aqui está o prompt que usei para começar:

Eu preciso criar um serviço web que controlará meu instrumento usando URLs básicas (via um navegador web). Não sei muito sobre serviços web ou frameworks, mas estou familiarizado com Python. Escreva o código Python completo para alcançar essa tarefa.

Aqui está a classe que controla meu instrumento:

<pre><code>```

{código acima}

```

</code></pre>

E a (resposta parcial):

Resposta do Prompt do ChatGPT

Figura 2: Resposta do prompt do ChatGPT

Minha parte favorita sobre os LLMs sofisticados (pagos) é que eles realmente decompõem a tarefa para você, educam e fornecem uma solução bastante boa como uma primeira iteração. Em Gemini vs. ChatGPT: Quem Escreve Melhor Código? eu comparei os dois LLMs um contra o outro e (alerta de spoiler) descobri que a versão mais recente e avançada do Gemini do Google era realmente muito boa (se não equivalente ao ChatGPT 4). Usar qualquer um desses LLMs resultará em um resultado semelhante ao mostrado acima.

Se eu quiser colocar isso em uma classe ou reformatar, posso simplesmente responder ao chat e fazer meu pedido. Quer seu código comentado? Sem problema, é só pedir!

Prompt: Adicione blocos de comentários no estilo docstring a cada função. Reescreva toda a classe como resultado para que eu possa copiar e colar de volta no meu editor de código.

Prompt do ChatGPT

Figura 3: Próxima resposta do prompt do ChatGPT

Testes

Agora que tivemos a IA Generativa criar o módulo Python, podemos pedir para ela escrever testes para nós ou nos mostrar como testar manualmente:

URL de Teste

Figura 4: URL de teste manual do ChatGPT

Teste Automatizado

 Figura 5: Teste automatizado escrito pelo ChatGPT

Após executar (ou ajustar e então executar) esses testes, deveríamos ser capazes de validar nosso novo módulo Python que faz a interface entre a web e nosso instrumento. 

Conclusão

Neste artigo, montamos um módulo Python que controlava nosso instrumento aproveitando código existente na web e IA Generativa. Após nosso LLM completar o módulo, introduzimos um novo módulo que atuava como intermediário entre a Internet e o próprio instrumento (via um serviço web). Também demos uma rápida olhada em como a IA Generativa pode nos guiar por todo o processo, incluindo testes manuais ou automatizados. A melhor parte deste exercício é que, se feito corretamente, deveria ter levado muito pouco tempo para montar. A primeira vez pode exigir um esforço extra, mas repetir esse processo para muitos instrumentos deve ser fácil (e incorrer em muito pouco tempo de desenvolvimento). Está claro que a IA Generativa mudou completamente a paisagem para todos nós e este artigo realmente demonstra isso. Esperamos que você se sinta inspirado a criar o próximo conjunto de bibliotecas de instrumentos aproveitando a IA Generativa e contribuir com elas para o resto da comunidade.

Todos os códigos-fonte usados neste projeto podem ser encontrados em: https://gitlab.com/ai-examples/instrument-controllables.

Sobre o autor

Sobre o autor

Ari is an engineer with broad experience in designing, manufacturing, testing, and integrating electrical, mechanical, and software systems. He is passionate about bringing design, verification, and test engineers together to work as a cohesive unit.

Recursos relacionados

Documentação técnica relacionada

Retornar a página inicial
Thank you, you are now subscribed to updates.