Visando automatizar medidas de Respirometria em Lodo Biológico iniciamos o uso da placa Arduino para fazer a conversão Analógico-Digital de um transmissor de Oxigênio Dissolvido (OD) da marca Mettler Toledo (mod. 4050e).
Este não é um medidor adequado para uso em bancada mas para a montagem em um painel de instrumentos. E é um modelo que não é mais fabricado desde 2007.
Conforme o manual deste medidor (disponível em Manual_MettlerToledo_4050e.pdf) este instrumento possui duas saídas analógicas, uma para OD e outra para Temperatura, que podem ser configuradas para gerar uma corrente de 0-20mA ou 4-20 mA proporcional à concentração de OD e/ou à Temperatura.
Decidimos utilizar uma placa Arduino (mod. Duemilanove), como interface AD, para converter os sinais analógicos de corrente (do medidor de OD) para sinais digitais (para um PC) e escrever uma interface gráfica em Tcl/Tk (supervisório) para automatizar a aquisição das leituras de OD e Temperatura e consequentemente automatizar medidas de Respirometria em Lodo Biológico.
Utilizamos o Linux Debian 6.0 (Squeeze) como ambiente de desenvolvimento e as informações sobre a instalação dos programas necessários estão disponíveis na seção Instalação da IDE do Arduino no Debian 6.0 (Squeeze).
O medidor possui, na parte traseira, conexões para o eletrodo e saídas analógicas, dentre outras, conforme a figura abaixo.
Figura 179. Conexões na parte traseira do medidor de OD 4050e com destaque para as conexões 30 e 31 correspondente à saída analógica referentes à concentração de OD.
Seguindo o manual do medidor fizemos as configurações necessárias para gerar uma corrente de 4mA para a concentração de 0,00 mg/L de OD e 20mA para a concentração de 9,00 mg/L de OD. Também foi ativado o recurso de gerar uma corrente constante de 22mA (corrente de saturação) para quaisquer concentrações maiores do que 9,00 mg/L de OD.
Figura 180. Gráfico da corrente (mA) gerada pelo medidor 4050e em função da concentração de OD (mg/L).
A corrente mínima de 4mA, para [OD] = 0,00 mg/L, tem uma utilidade prática pois permite identificar uma eventual ruptura do circuito. Ou seja, uma corrente de 0mA indica que o circuito está “aberto”.
O tutorial http://arduino.cc/en/Tutorial/AnalogReadSerial mostra os comandos básicos para a conversão de um valor de voltagem em um valor numérico adimensional, na faixa de 0 a 1023, e o envio dos dados pela saída serial. Enquanto que o tutorial http://arduino.cc/en/Tutorial/ReadAnalogVoltage além das etapas anteriores mostra também como fazer a conversão das leituras em valores de voltagem (mV).
Os termos “Tensão” e “Voltagem ” são usados muitas vezes como sinônimos mas alguns profissionais da área de Eletrônica podem ficar (muito) incomodados com isso!
Peço a compreensão dos profissionais da Eletrônica mas preferi usar o termo “Voltagem ” ao longo do texto.
Gostaria apenas de lembrar que o livro Princípios de Análise Instrumental Skoog, 2002 utiliza o termo “Voltagem ”.
Os pinos analógicos do Arduino (ANALOG IN), usados para leituras analógicas de diversos sensores, suportam uma voltagem de no máximo 5V, por isso colocamos em série com a saída do medidor (pinos 31+ e 30-) um resistor variável (resistência shunt) ajustado para 227 Ohms, para obter uma leitura de no máximo de 5 V (4,994 V) quando o transmissor gerar uma corrente de 22 mA (corrente máxima de saturação). O pino 31(+) do medidor foi conectado ao pino A0 do Arduino e o pino 30(-) do medidor conectado ao Terra(Gnd) da placa Arduino.
Figura 181. Diagrama das conexões entre o medidor 4050e e a placa Arduino (Duemilanove) para a conversão analógico digital das medidas de OD.
Usamos como ponto de partida o Sketch disponível no tutorial http://arduino.cc/en/Tutorial/ReadAnalogVoltage, e após algumas adaptações utilizamos o seguinte código para os testes iniciais:
/* ReadAnalogVoltage Lê a entrada analógica no pino 0, coverte o valor para tensão, e evia o resultado pela porta serial USB Este código é de Domínio Público */ int i = 0; // variavel de contagem float soma = 0; // variavel que soma os valores obtidos float media = 0; // variavel que calcula a media void setup() { // Inicializa a comunicação serial com 9600 bits por segundo // O padrão de comunicação serial para a placa Arduino é // 8 bits de dados, sem paridade (n) e 1 bit de parada (8,n,1) Serial.begin(9600); } // A rotina loop é executada indefinidamente void loop() { soma = 0; i = 0; media = 0; while(i < 10) { // ler sinal analogico no pino 0: int sensorValue = analogRead(A0); soma = soma + sensorValue; i++; delay(100); } media = soma/10; // Converter leitura analogica (0 - 1023) em voltagem (0 - 5V): float voltage = media * (5.0 / 1023.0); // print exibe sem salto de linha //Serial.print("Voltagem "); // O número 5 define o número de casas decimais // println exibe com salto de linha Serial.println(voltage, 5); delay(50); }
Nos testes iniciais observamos que as leituras são influenciadas pela presença da resistência externa tornando mais instável as leituras no display do medidor de OD.
Por isso incluímos um loop de amostragem para cálculo da média de 10 leituras no programa de aquisição do Arduino seguindo como exemplo o código disponível em http://labduino.blogspot.com.br/2011/08/calculando-media-com-o-arduino.html.
O conversor Analógico-Digital (AD) da placa Arduino possui uma resolução[16] de 10 bits, ou seja, consegue converter a escala de 0-5V com uma resolução de:
210 = 1024
Ou seja tem a resolução de uma parte em (1024) e portanto se a faixa medida é de 0-5 V, a resolução será:
resolução = 5 V / (1024) = 0,00488 ou 4,88 mV
Para [OD] = 0,00 mg/L a corrente gerada no medidor é de 4mA e portanto a voltagem através da resistência de 227 Ohms é 0,91 V (227 Ohms x 0,004 A).
E quando [OD] = 9,00 mg/L, a corrente gerada no medidor é de 20mA, gerando uma voltagem através da resistência de 227 Ohms de 4,54 V (227 Ohms x 0,020 A).
Portanto a faixa de leitura de [OD] (0,00 a 9,00 mg/L) corresponde a um intervalo de voltagem de 3,63 V (0,91 V - 4,54 V).
O gráfico [OD] (mg/L) X Voltagem (V) possui uma inclinação de:
(9,00 mg/L - 0,00 mg/L) / (4,54 V - 0,91 V) = 2,48 mg/L*V
Figura 182. Gráfico da voltagem (V) gerada pelo medidor 4050e em função da concentração de OD (mg/L), com inclinação de 2,48 mg/L*V.
Portanto se a resolução das leituras de voltagem da placa Arduino (10 bits) é 4,88 mV podemos estimar a resolução das leituras de [OD], no intervalo considerado, pelo produto:
2,48 (mg/L*V) * 0,00488 (V) = 0,01 mg/L
Lembrar que essa resolução de leitura é válida para os intervalos de concentração de OD definidos na configuração do medidor!
Nessa etapa inicial usamos o programa de aquisição (femto600s.tcl) como protótipo para o desenvolvimento de uma interface para aquisição de dados.
Para organizar o algoritmo de cálculo de [OD] a partir das leituras de voltagem realizadas pela placa Arduino foram definidas as seguintes variáveis:
LIC
- Limite Inferior de Corrente do transmissor (Ex: 0,004 A)
LSC
- Limite Superior de Corrente do transmissor (Ex: 0,020 A)
LSat
- Limite de Saturação do transmissor (Ex: 0,022 A)
R
- Resistência utilizada para converter a corrente do transmissor em voltagem para leitura pela placa Arduino (227 Ohms)
LIV
- Limite Inferior de Voltagem = R
* LIC
= 227 Ohms x 0,004 A = 0,91 V
LSV
- Limite Superior de Voltagem = R
* LSC
= 227 Ohms x 0,020 A = 4,54 V
LV_Arduino
- Limite de Voltagem que pode ser aplicada nas entradas analógicas da placa Arduino (5V)
OD_LIC
- Concentração de Oxigênio Dissolvido associada ao LIC
(Ex: 0,00 mg/L)
OD_LSC
- Concentração de Oxigênio Dissolvido associado ao LSC
(Ex: 9,00 mg/L)
OD_LIV
- Concentração de Oxigênio Dissolvido associada ao LIV
= OD_LIC
OD_LSV
- Concentração de Oxigênio Dissolvido associada ao LSV
= OD_LSC
Res_V
- Resolução das leituras de voltagem pela placa Arduino = 5 V / (1024 -1) = 4,88 mV
Res_OD
- Resolução das leituras de OD = 0,01 mg/L
Também podemos formalizar o cálculo da resolução das leituras de OD pela fórmula:
Decidimos dividir as atividades de aquisição em duas etapas:
A placa Arduino faz a aquisição das leituras de voltagem e envia os dados das múltiplas entradas em apenas uma linha pela porta serial USB.
A interface (escrita em Tcl/Tk) faz a leitura dos dados de tensão, extrai os campos referentes aos diferentes padrões e faz a conversão das leituras de voltagem para os parâmetros correspondentes utilizando as respectivas equações de calibração.
Nessa etapa inicial usamos como ponto de partida o programa de aquisição (femto600s.tcl) o qual foi renomeado para arduino_4050e.tcl.
Conforme pode ser verificado na listagem do programa, foram definidas algumas variáveis que são utilizadas para o cálculo dos parâmetros da equação de calibração no procedimento curva_cal pontos
(Fonte: Linear regression and correlation coefficient).
Os parâmetros de equação de calibração “linear” são passados como parâmetros para o procedimento converter x a b
.
Listagem parcial do programa arduino_4050e.tcl:
#!/bin/sh #A próxima linha reinicia usando o wish \ exec wish "$0" "$@" #11/03/2013 #Programa básico para aquisição de leituras #de voltagem de uma placa Arduino convertendo #leituras de OD e Temperatura de um transmissor Mettler Toledo 4050e #==================================================================================== #Definindo as "constantes" para o cálculo dos parâmetros #da curva de calibração para conversão das leituras de voltagem (V) #nas respectivas unidades dos parâmetros monitorados #As constantes: LIC, LSC, LSat, OD_LIC, OD_LSC, T_LIC e T_LSC #são configurados manualmente no transmissor 4050e #LV_Arduino = Limite superior de voltagem que pode ser aplicada nas #entradas analógicas da placa Arduino (5V) #A constante R (227 Ohms) corresponde à resistência usada no circuito para conversão #de corrente em voltagem e é definida em função de LSat (0,022 A) e LV_Arduino (5 V) #LIC = Limite Inferior de Corrente do transmissor (Ex: 0,004 A) #LSC = Limite Superior de Corrente do transmissor (Ex: 0,020 A) #LSat = Limite de Saturação do transmissor (Ex: 0,022 A) #O LSat especifica qual o valor de corrente que será gerada para #uma concentração de OD maior do que o OD_LSC set LIC 0.004 set LSC 0.020 set LSat 0.022 #OD_LIC = Concentração de Oxigênio Dissolvido associada ao LIC (Ex: 0,00 mg/L) #OD_LSC = Concentração de Oxigênio Dissolvido associado ao LSC (Ex: 9,00 mg/L) set OD_LIC 0.00 set OD_LSC 9.00 #R = Resistência utilizada para converter a corrente do transmissor #em voltagem para leitura pela placa Arduino ( 227 Ohms). set R 232 #==================================================================================== #Variáveis calculadas #LIV = Limite Inferior de Voltagem = R * LIC #LSV = Limite Superior de Voltagem = R * LSC set LIV [expr $R * $LIC] set LSV [expr $R * $LSC] #OD_LIV = Concentração de Oxigênio Dissolvido associada ao LIV = OD_LIC #OD_LSV = Concentração de Oxigênio Dissolvido associada ao LSV = OD_LIC set OD_LIV $OD_LIC set OD_LSV $OD_LSC puts "$LIC $LSC $LIV $LSV $LSat $OD_LIV e $OD_LSV" #==================================================================================== #Dados para o cálculo dos parâmetros de calibração de OD set pontos_OD [list [list $LIV $OD_LIV] [list $LSV $OD_LSV] ] #Dados para o cálculo dos parâmetros de calibração de Temperatura #set pontos_T [list [list $LIV $T_LIV] [list $LSV $T_LSV] ] #==================================================================================== #Variáveis para cálculo da média global porta frame .botoes pack .botoes -side bottom -fill x button .botoes.iniciar -text "Iniciar Leitura" -command { abrir_porta } button .botoes.parar -text "Parar Leitura" -command { close $porta } button .botoes.gravar -text "Gravar Arquivo" -command { gravar_arquivo } button .botoes.sair -text " Sair " -command "exit" pack .botoes.iniciar .botoes.parar .botoes.gravar .botoes.sair \ -side left -expand yes -fill both frame .tela pack .tela -side top -fill x text .tela.dados -relief sunken -yscrollcommand {.tela.rolagem set} \ -background white -width 60 scrollbar .tela.rolagem -command {.tela.dados yview} pack .tela.dados -side left -fill y pack .tela.rolagem -expand yes -fill both ################################################################ #Procedimento abrir_porta ################################################################ proc abrir_porta { } { global t0 global porta global media soma cont N set media 0.0 set soma 0.0 set cont 0 set N 5.0 set porta [ open /dev/ttyUSB0 r+ ] fconfigure $porta -mode 9600,n,8,1 fileevent $porta readable [list ler_porta $porta] set t0 [clock clicks -milliseconds] .tela.dados insert end "\nTempo(ms) Leituras\n\n" } ################################################################ #Procedimento ler_porta ################################################################ proc ler_porta { canal } { global t0 OD_cal_incl OD_cal_int global cont soma media N #Comando para calcular o tempo atual em milisegundos set tn [clock clicks -milliseconds] #Comando para calcular o tempo decorrido desde t0 em segundos set tn [expr ($tn - $t0)/1000.0] if { [eof $canal ] } { puts stderr "Fechando $canal" catch { close $canal } return } set dados [gets $canal] #Comando regsub usado para substituir as ocorrências de . por , #É possível usar \\. e \\, ou {\.} e {,} ou {,} set tn [regsub {\.} $tn \, ] set OD [converter $dados $OD_cal_incl $OD_cal_int] if {$cont < $N} { set soma [expr $soma + $OD] incr cont puts "soma: $soma cont: $cont" } else { set media [expr $soma / $N] puts "media: $media" .tela.dados insert end "Média de OD: $media\n" set cont 0 set soma 0.0 } set dados [regsub {\.} $dados {,} ] set OD [regsub {\.} $OD {,} ] .tela.dados insert end " $tn $dados $OD\n" .tela.dados see end } ################################################################ #Procedimento gravar_arquivo ################################################################ proc gravar_arquivo { } { set dados [.tela.dados get 1.0 {end -1c}] set tipo_arquivo { {"Arquivos Texto" { .txt .TXT } } {"Todos os arquivos" * } } set nome_arquivo [tk_getSaveFile -filetypes $tipo_arquivo \ -initialdir pwd -defaultextension .txt] if {[catch {set id_arquivo [open $nome_arquivo w]} result] != 0} { return } puts -nonewline $id_arquivo $dados close $id_arquivo } ################################################################ #Procedimento para o cálculo dos parâmetros de uma regressão #linear retornando a(coef. angular), b(interseção) e #r(coef. correlação #Fonte: Linear regression and correlation coefficient #http://wiki.tcl.tk/819 ################################################################ proc curva_cal pontos { # linear regression y=ax+b for {{x0 y0} {x1 y1}...} # returns {a b r}, where r: correlation coefficient set N 0 foreach i {Sx Sy Sxy Sx2 Sy2} { set $i 0.0 } foreach ponto $pontos { foreach {x y} $ponto break set Sx [expr {$Sx + $x}] set Sy [expr {$Sy + $y}] set Sx2 [expr {$Sx2 + $x*$x}] set Sy2 [expr {$Sy2 + $y*$y}] set Sxy [expr {$Sxy + $x*$y}] incr N } set t1 [expr {$N*$Sxy - $Sx*$Sy}] set t2 [expr {$N*$Sx2 - $Sx*$Sx}] set a [expr {double($t1)/$t2}] set b [expr {double($Sy-$a*$Sx)/$N}] set r [expr {$t1/(sqrt($t2)*sqrt($N*$Sy2-$Sy*$Sy))}] # puts "$a $b $r" #Retorna o coeficiente angular "a" e o coeficiente linear "b" #da regressão linear return [list $a $b] } ;#RS #Lista contendo os parâmetros de calibração para OD set OD_par_cal [curva_cal $pontos_OD] #Coeficiente angular para calibração de OD set OD_cal_incl [lindex $OD_par_cal 0] #Coeficiente linear para calibração de OD set OD_cal_int [lindex $OD_par_cal 1] #Procedimento para conversão das leituras de voltagem #para o parâmetro de interesse proc converter { x a b } { return [expr $a * $x + $b] }
Fizemos os testes iniciais com R
= 227 Ohms mas observamos uma diferença entre as leituras feitas pelo Arduino e o display do medidor. Alteramos o valor de R
no código do programa para reduzir a diferença e após várias tentativas chegamos experimentalmente no valor de 232 Ohms.
Nos testes iniciais observamos que as leituras do medidor tornam-se mais instáveis quando iniciamos a aquisição de dados com a placa Arduino.
Por exemplo, as leituras do transmissor, com a placa Arduino desligada, oscila entre 7,55 e 7,57 mg/L (variação na segunda casa decimal) mas ao iniciar a aquisição as leituras passam a oscilar entre 7,00 e 7,40 mg/L (variação na segunda casa decimal).
Acreditamos que essa oscilação se deve à “drenagem” de corrente do medidor para o Arduino durante a leitura.
Por isso decidimos usar o Amplificador Operacional TL084CN como seguidor de voltagem isolar o medidor do circuito de aquisição (evitando drenagem de corrente) para reduzir as oscilações nas leituras de OD.
O TL084 é um circuito integrado com quatro Amplificadores Operacionais conforme mostra a figura seguinte.
Para conhecer mais detalhes desse modelo consulte o datasheet no link: http://www.st.com/web/en/resource/technical/document/datasheet/CD00000493.pdf
Para entender melhor o funcionamento dos amplificadores operacionais (e outros componentes) visite o site de simulações eletrônicas: http://www.falstad.com/circuit/e-index.html e conheça os tutoriais do site www.centelhas.com.br/biblioteca
A figura seguinte mostra um Amplificador Operacional como um Seguidor de Voltagem, no qual o sinal de entrada é conectado na entrada não-inversora e a saída é conectada na entrada inversora.
O seguidor de voltagem (ou tensão) tem a vantagem de não exigir (drenar) corrente do sinal de entrada, é o circuito interno do amplificador operacional e a fonte de alimentação que fornecem a corrente na saída do amplificador operacional, e por isso Vi = Vo Skoog, 2002
Figura 187. Diagrama das conexões entre o medidor 4050e, o amplificador operacional (como seguidor de voltagem) e a placa Arduino para a conversão analógico digital das medidas de OD.
A alimentação do amplificador operacional foi feito com duas fontes de alimentação de 12 V, nas quais foram cortados os pinos “terra” e interligadas conforme a figura seguinte:
Figura 188. Diagrama das conexões de duas fontes de 12V para alimentação do amplificador operacional.
Lembrar que a resistência deve estar antes do AO para que o medidor de OD gere uma corrente, já que o parâmetro de saída do medidor é corrente. Para diferentes resistências o medidor gera uma corrente correspondente à [OD]. Se as saídas do medidor estiverem abertas (resistência infinita) o medidor vai manter aplicar a voltagem máxima considerando que o sistema está com alta resistência!
O uso do amplificador operacional reduziu significativamente a oscilação das leituras como mostra a figura seguinte.
Figura 190. O gráfico da esquerda mostra uma sequência de leituras de OD sem o uso do amplificador operacional como seguidor de voltagem, e o gráfico da direita mostra a redução significativa das oscilações com o uso do amplificador operacional.
Mais tarde encontramos uma outra sugestão para minimizar a interferência do circuito de aquisição (Arduino) nas leituras do medidor, conforme figura seguinte.
Figura 191. Circuito alternativo para minimizar a interferência do circuito de aquisição (Arduino) nas leituras de um medidor (Fonte: http://forum.arduino.cc/index.php/topic,19613.0.html
[16] Para entender o conceito de “resolução” na conversão AD consulte o tutorial http://emc5710.lago.prof.ufsc.br/arquivos/5conversao AD 122.pdf