Guia de Uso - Placas NIDAQ + Python
O que é este guia?
Este guia foi escrito para novos membros do GCOM (Grupo de Controle e Modelagem). O objetivo desta seção é desmistificar a utilização de placas de aquisição de dados da National Instruments (NIDAQ - National Instruments Data Acquisition USB Devices) utilizando Python como linguagem de programação.
- OBSERVAÇÃO 1: para utilizar este guia, o usuário deverá estar familiarizado com a linguagem Python, bem como instalação de bibliotecas.
- OBSERVAÇÃO 2: a biblioteca nidaqmx será usada como base neste guia. Para instalá-la, use o comando:
Aqui expressamos publicamente nossa gratidão aos autores da biblioteca.
- OBSERVAÇÃO 3: o driver USB da placa de aquisição de dados precisa estar instalado. No momento da escrita deste guia, o download podia ser realizado por este link, após um registro gratuito em www.ni.com. Alternativamente, o usuário pode instalar drivers utilizando também o comando:
Recomendamos a primeira opção como o padrão.
IMPORTANTE: esta é uma versão muito resumida para uso rápido. Maiores detalhes podem ser encontrados (em inglês) em https://pypi.org/project/nidaqmx/
Tarefas (Task)
Uma tarefa é um conjunto de canais virtuais com temporização e outras propriedades. Resumidamente, são necessárias tarefas para aquisição e envio de dados. Maiores informações aqui.
Para criar uma tarefa, use o seguinte comando:
import nidaqmx # Importa a biblioteca
with nidaqmx.Task() as task: # Cria a tarefa
pass # Aqui você deve digitar o código que deverá ser executado naquela tarefa.
Canais Virtuais
Um canal virtual é um pedaço de software que encapsula o canal físico juntamente com informações a seu respeito (faixa de medição, configuração dos terminais e outras) que formatam os dados. Por outro lado, um canal físico é o terminal em que você mede ou gera sinais analógicos ou digitais, sendo que um canal físico pode incluir mais que um terminal ( caso de entrada analógica diferencial).
IMPORTANTE: cada canal físico tem um nome único (exemplos: Dev1/ao1) a depender do nome do dispositivo (configurável via NI-MAX). Para maiores informações acesse aqui.
A seguir um exemplo de código de como adicionar um canal de entrada analógica a uma tarefa, configurando range e lendo um dado:
import nidaqmx
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0", min_val=-10.0, max_val=10.0)
task.read()
AIChannel(name=Dev1/ai0)
0.54875412354412544
Para adicionar múltiplos canais a uma tarefa e configurá-los:
import nidaqmx
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0", min_val=-5.0, max_val=5.0)
task.ai_channels.add_ai_voltage_chan("Dev1/ai1", min_val=-10.0, max_val=10.0)
task.read()
AIChannel(name=Dev1/ai0)
AIChannel(name=Dev1/ai1)
[1.12345897042644564, -2.1234589701454564]
Temporização da Sessão e Período de Amostragem
Você pode usar a placa de aquisição de dados da National para computar o tempo entre duas amostras (período de amostragem) ou o próprio clock de seu computador. Esteja ciente que a utilização de placas de aquisição de dados para temporização da sessão/cômputo do período de amostragem (temporização por hardware) é significativamente mais eficiente que a utilização de temporização por software (pelo computador).
Para adquirir sinais utilizando temporização por harware:
import nidaqmx
from nidaqmx.constants import AcquisitionType, READ_ALL_AVAILABLE
with nidaqmx.Task() as task:
task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=10)
data = task.read(READ_ALL_AVAILABLE)
print("Acquired data: [" + ", ".join(f"{value:f}" for value in data) + "]")
AIChannel(name=Dev1/ai0)
Acquired data: [-0.149693, 2.869503, 4.520249, 4.704886, 2.875912, -0.006104, -2.895596, -4.493698, -4.515671, -2.776574]
DIFF, RSE e NRSE
Há uma diferença entre métodos de coleta de dados. Usando a configuração terminal
- DIFF (Differential): os terminais físicos vão medir a diferença de potencial entre dois terminais físicos (AI+ e AI-). Esta é preferível quando se tem ruído de modo comum. Evita, ainda, loops de terra
- RSE (Referenced Single-Ended): nesta configuração usa-se o terra do chassi do dispositivo DAQ como referência. Utiliza apenas uma entrada física por canal (ao contrário do DIFF, que usa duas). Entretanto, apresenta maior susceptibilidade a ruído de modo comum e loops de terra.
- NRSE (Non-Referenced Single-Ended): usa uma referência de terra compartilhado por todos os canais. Não possui, necessariamente, o terra do chassi do dispositivo. Permite uma conexão específica para o terra para todos os canais.
Exemplo:
import nidaqmx
from nidaqmx.constants import AcquisitionType, READ_ALL_AVAILABLE, TerminalConfiguration
with nidaqmx.Task() as task:
# ATENÇÃO: DESCOMENTE UMA DAS LINHAS ABAIXO, CONFORME CONFIGURAÇÃO TERMINAL DESEJADA
#task.ai_channels.add_ai_voltage_chan("Dev1/ai0", terminal_config=TerminalConfiguration.DIFF)
#task.ai_channels.add_ai_voltage_chan("Dev1/ai1", terminal_config=TerminalConfiguration.RSE)
#task.ai_channels.add_ai_voltage_chan("Dev1/ai2", terminal_config=TerminalConfiguration.NRSE)
task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=10)
data = task.read(READ_ALL_AVAILABLE)
print("Acquired data: [" + ", ".join(f"{value:f}" for value in data) + "]")
AIChannel(name=Dev1/ai0)
Acquired data: [-0.149693, 2.869503, 4.520249, 4.704886, 2.875912, -0.006104, -2.895596, -4.493698, -4.515671, -2.776574]
Envio de dados - Analog Output
Podemos usar canais de saída para gerar sinais de tensão pela placa de aquisição de dados da National. Abaixo um exemplo de como utilizar o canal analógico ao0 (analog output 0) para enviar um sinal de tensão utilizando uma tarefa com o método write:
import nidaqmx
from nidaqmx.constants import AcquisitionType
with nidaqmx.Task() as task:
data = []
total_samples = 1000
task.ao_channels.add_ao_voltage_chan("Dev1/ao0")
task.timing.cfg_samp_clk_timing(
1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=total_samples
)
data = [5.0 * i / total_samples for i in range(total_samples)]
number_of_samples_written = task.write(data, auto_start=True)
print(f"Generating {number_of_samples_written} voltage samples.")
task.wait_until_done()
task.stop()