26. Válvula de 3 vias Controlada por Servomotor

Comecei a estudar o uso de servomotores com a intenção de usá-los para automatizar o controle de torneiras de 3 vias para a montagem de sistemas de análise em fluxo, como mostra a figura 320.

Figura 320. Servomotor controlando uma torneira de 3 vias (Fonte: Adding an actuated flow selector valve to our syringe pump)

Servomotor controlando uma torneira de 3 vias (Fonte: Adding an actuated flow selector valve to our syringe pump)

Nas seções seguintes vamos descrever os módulos (físicos e lógicos) do sistema e como fazer a integração dos mesmos para a montagem de válvulas que permitam o controle de pequenas vazões em sistemas de análise em fluxo.

26.1. Módulos

26.1.1. Torneira (ou Válvula) de 3 Vias

Para entender o funcionamento dessas válvulas vamos representar uma Torneira de 3 Vias por um diagrama esquemático como mostra a figura 321.

Figura 321. Diagrama esquemático de uma torneira (ou válvula) de 3 vias.

Diagrama esquemático de uma torneira (ou válvula) de 3 vias.

Agora vamos entender como podemos fazer a comutação dos fluxos entre 3 diferentes reservatórios fazendo rotações de 90° na torneira como mostra a figura 321.

Figura 322. Na posição 1 os reservatórios A, B e C estão conectados entre si. Após girar a torneira em 90° no sentido horário (Posição 2), os reservatórios A e B ficam interconectados e o reservatório C fica isolado. Após mais um giro de 90 ° no sentido horário (Posição 3), os reservatórios A e C ficam conectados e o reservatório B fica isolado. E finalmente após mais um giro de 90° no sentido horário (Posição 4), os reservatórios B e C ficam interconectados e o reservatório A fica isolado. Mais um giro de 90° leva de volta para a posição 1.

Na posição “1” os reservatórios A, B e C estão conectados entre si. Após girar a torneira em 90° no sentido horário (Posição 2), os reservatórios A e B ficam interconectados e o reservatório C fica isolado. Após mais um giro de 90 ° no sentido horário (Posição 3), os reservatórios A e C ficam conectados e o reservatório B fica isolado. E finalmente após mais um giro de 90° no sentido horário (Posição 4), os reservatórios B e C ficam interconectados e o reservatório A fica isolado. Mais um giro de 90° leva de volta para a posição 1.

Nota

Mas é importante lembrar que o controle de uma torneira de 3 vias por um servomotor convencional está restrito ao limite de rotação de 180° dos servomotores.

Ou até menos (~120°), como foi o caso do servomotor que compramos.

Por exemplo, vamos imaginar uma aplicação na qual vamos usar um servomotor com giro máximo de ~120° para adicionar no reservatório A quantidades conhecidas dos reagentes contidos nos reservatórios B e C. Nesse caso seria necessário comutar o fluxo entre três reservatórios e executar apenas uma rotação de 90° e ~30° para bloquear as três saídas como mostra a figura 323.

Figura 323. Na posiçao 1 é possível transferir amostra ou reagente de B para A. Após um giro de 90° no sentido horário é possível transferir amostra ou reagente de C para A. E com mais um pequeno giro de ~30° no sentido horário todas as conexões ficam fechadas.

Na posiçao 1 é possível transferir amostra ou reagente de B para A. Após um giro de 90° no sentido horário é possível transferir amostra ou reagente de C para A. E com mais um pequeno giro de ~30° no sentido horário todas as conexões ficam fechadas.

26.1.2. Servomotor

Os servomotores realizam rotações, com precisão, mas restritas a uma faixa de 0 a 180°. Eles possuem um pequeno motor conectado através de engrenagens a um eixo central que está ligado a um braço externo e a um potenciômetro. O potenciômetro gera um sinal para um circuito interno que controla a posição do eixo. (Figura 324)

Figura 324. Diagrama esquemático dos componentes de um servomotor (Fonte: Arduino Cookbook)

Diagrama esquemático dos componentes de um servomotor (Fonte: Arduino Cookbook)

Os servomotores possuem 3 fios: fase ou positivo (vermelho), terra ou negativo (preto ou marrom) e sinal de controle (amarelo, laranja ou branco). O fio vermelho deve ser ligado em 5V, o fio preto no terra e o fio de controle deve ser ligado a um dos pinos digitais com saída PWM da placa Arduino (pinos 3, 5, 6, 9, 10 e 11, com sinal "~").

Os servos são controlados com a aplicação de pulsos no fio de controle. Com um pulso curto de 1ms ou menos o servomotor gira para um extremo e um pulso longo de 2ms faz o servo girar para o outro extremo. Pulsos em valores intermediários fazem o servo girar com ângulos proporcionais à largura do pulso, como mostra a figura 325.

Figura 325. Diagrama esquemático dos componentes de um servomotor (Fonte: Arduino Cookbook)

Diagrama esquemático dos componentes de um servomotor (Fonte: Arduino Cookbook)

Atenção

Mas os pulsos usados para o controle de servos são diferentes dos pulsos PWM gerados com o comando analogWrite.

E um servomotor pode ser danificado se for usado o pulso PWM gerado pelo comando analogWrite.

Por isso deve sempre ser usado o comando da biblioteca Servo.h para o controle de servomotores com a placa Arduino.

Dica

As primeiras versões da biblioteca Servo.h permitiam o controle de um servo apenas pelos pinos digitais 9 e 10. Mas as versões recentes permitem o uso de qualquer pino digital para controle de um servo.

Alguns links sobre a biblioteca Servo.h:

Então providenciei a compra do servomotor Micro Servo 9g SG90 da Tower Pro (Datasheet) e fiz os primeiros testes de controle com o Arduino usando o seguinte código:

#include <Servo.h>

#define SERVO 9 // Porta Digital 9 PWM

Servo s; // Variável Servo
int pos; // Posição Servo

void setup ()
{
  s.attach(SERVO);
  Serial.begin(9600);
  s.write(0); // Inicia motor posição zero
}

void loop()
{
  for(pos = 0; pos < 180; pos++)
  {
    s.write(pos);
    delay(15);
  }
delay(1000);
  for(pos = 180; pos >= 0; pos--)
  {
    s.write(pos);
    delay(15);
  }
}

Em seguida conectei uma torneira de 3 vias para verificar se esse servomotor era capaz de controlar a torneira e pude observar que o torque era suficiente para girar a torneira mas, aparentemente, exigindo muito esforço do motorzinho.

Então resolvi comprar um modelo com maior torque e escolhi um genérico do tipo Futaba S3003.

Esse servomotor deve ser alimentado por uma fonte externa de ~6V com capacidade de fornecer pelo menos 400mA (Fonte: Standard S3003 Servo - www.kitronik.co.uk/).

O único requisito é fazer o aterramento comum entre a placa Arduino e a fonte externa como mostra a figura 326.

Figura 326. Diagrama do circuito para alimentação de um servomotor com fonte externa (Fonte: Arduino: How to Use a Servo Motor With an External Power)

Diagrama do circuito para alimentação de um servomotor com fonte externa (Fonte: Arduino: How to Use a Servo Motor With an External Power)

Segundo a mensagem: Dúvida Servo Futaba S3003?, esse modelo de servomotor opera com tensão de 4,8-6V e demanda corrente na faixa de 300 mA.

Segundo os manuais, um servomotor é capaz de realizar rotações de até 180°. Mas nos primeiros testes pude verificar que o motor que eu havia adquirido girava, no máximo120°.

Felizmente, para a nossa aplicação, isso não representa um grande problema. Mas dependendo do projeto isso pode inviabilizar o uso do motor.

Pedi ajuda no fórum https://forum.arduino.cc (Which version of servo.h is able to use any digital pin? e https://forum.arduino.cc (Servo don't rotate more than ~120 degrees) e fui informado que não é incomum encontrar servos que não giram 180°.

Também foi sugerido experimentar o comando writeMicroseconds() e experimentar diferentes valores além do intervalo padrão (1000 - 2000), mas tomando cuidado pois valores fora desses limites podem gerar altas correntes e danificar o servo.

Então fiz alguns testes com o comando writeMicroseconds() variando o intervalo de tempo de 1000 até 600 e de 2000 até 2400 conforme o código:

#include <Servo.h>

#define SERVO 9 // Porta Digital 9 PWM

Servo myservo; // Variável Servo
int pos; // Posição Servo

void setup ()
{
  myservo.attach(SERVO);
  Serial.begin(9600);
  myservo.write(1500); // Inicia motor posição zero
}

void loop()
{
  for(pos = 600; pos < 2400; pos = pos + 10)
  {
    myservo.writeMicroseconds(pos);
  delay(15);
  }
delay(2000);
  for(pos = 2400; pos >= 600; pos = pos - 10)
  {
    myservo.writeMicroseconds(pos);
    delay(15);
  }
  delay(4000);
  }

Mas o ângulo máximo de rotação continuou em ~120° e observei também que com o aumento da velocidade de rotação o motor apresentava variações na velocidade se movimentando aos saltos.

26.1.3. Interface de Controle

Para facilitar a automação do controle de uma torneira de 3 vias por um servomotor, seria conveniente implementar uma interface de controle que permitisse a conversão das posições da(s) válvula(s) em comandos para a placa Arduino que enviaria os comandos para o servomotor executar o deslocamento correto e fazer o alinhamento das conexões conforme desejado.

Isso poderia ser feito com um arquivo de configuração correlacionando as posições da torneira com diferentes ângulos de rotação.

Para o exemplo descrito na figura 323 poderíamos ter a seguinte tabela de conversão:

Tabela 28. Tabela de conversão das posições da torneira de 3 vias para o exemplo da figura 323

PosiçãoÂngulo
1 (conectado com o reservatório A)
2 (conectado com o reservatório B) 90°
3 (fechado) 120°

Portanto o desafio proposto é: Como montar uma interface de controle "genérica" para permitir a automação do controle das válvulas de 3 vias para o seu uso em sistemas de análise em fluxo com diferentes configurações?

A interface deve ser amigável, permitindo ao usuário fazer uma programação dinâmica em uma linguagem simples e de alto nível.

O primeiro passo é implementar um programa no Arduino (sketch) para receber comandos pela porta serial no formato:

[comando];[pino];[valor]

Essa foi a estratégia usada no código do projeto Sistema com Bombeamento e Detecção - Irrigador com balança.

Mas é importante lembrar que nos pinos digitais podem estar conectados servomotores ou relês que recebem comandos diferenciados.

E portanto o [comando] deve chamar uma função específica, definida no sketch para o tipo de dispositivo conectado ao pino digital da placa Arduino.

A campo [pino] define o pino digital ao qual está conectado o dispositivo: D2, D3 (PWM), D4, D5(PWM), D6(PWM), D7, D8, D9(PWM), D10(PWM), D11(PWM) ou D12.

E o campo [valor] especifica o valor numérico que deve ser enviado.

Por exemplo, podemos ter o comando:

SET_SERVO - dedefinir a posição de um servomotor.

Poderíamos pensar também no comando GET_SERVO para retornar a posição do servo, mas a maioria dos servos não retornam informações sobre o ângulo atual do servo.

Uma alternativa seria usar o comando read() mas ele não retorna a posição real do servo mas apenas o valor usado na última chamada do comando write().

Mas mesmo assim o comando read() poderia ser útil para checar a comunicação com a placa Arduino.

Exemplos de comandos:

SET_SERVO;S1;0 - servomotor 1 (S1) deve girar até a posição de 0°.

SET_SERVO;S2;90 - servomotor 2 deve girar até a posição de 90°.

GET_SERVO;S1 - retorna o ângulo do servomotor 1.

Também é possível usar essa estratégia e definir funções específicas para outros tipos de sensores ou atuadores ligados na placa Arduino.

SET_VALVE;V4;1 - definir o valor 1 (ON) da válvula 4 .

SET_PUMP;P9;200 - definir o valor 200 (PWM) à bomba 9.

GET_VALVE;V4 - retorna o estado (0/1) da válvula 4.

GET_LEVEL_SENSOR;S2 - retorna a leitura do sensor analógico 2

Nota

Com essa abordagem, o número do pino (digital/analógico) ligado ao dispositivo (servomotor, válvula, bomba ou sensor) deverá ser definido no código (Sketch) do Arduino.

Seguindo essa estratégia, emplementei o seguinte código para o Arduino:

#include <Servo.h>

int pos; // Posição Servo

const unsigned int MAX_INPUT = 40;
char message[MAX_INPUT];
char *cmd;
char *pin;
char *value;
char c;
byte length;
byte length_message;

Servo servo_1; // Variável Servo
Servo servo_2;


void setup ()
{

//Available pins
//D2, D3 (PWM), D4, D5(PWM), D6(PWM), D7, D8, D9(PWM), D10(PWM), D11(PWM) e D12
//A0, A1, A2, A3, A4 e A5

//Servo 1 ligado ao pino 9
  servo_1.attach(9);

  servo_1.write(0);

//Servo 2 ligado ao pino 10

  servo_2.attach(10);

  servo_2.write(0);
  
  Serial.begin(9600);
 
}

// here to process incoming serial data after a terminator received
void process_data (char *data) {
   
   cmd = strtok(data, ";");
  
     if ( (strcmp(cmd, "SET_SERVO") == 0) || (strcmp(cmd, "set_servo") == 0) ) {

      pin = strtok(NULL, ";");
      
      value = strtok(NULL, ";");

      setServo(pin, value); 
      
      } else if (strcmp(cmd, "GET_SERVO") == 0 || strcmp(cmd, "get_servo") == 0) {

        pin = strtok(NULL, ";");

        getServo(pin);
         
      } else {

        Serial.print("unknown command: ");
        Serial.println(cmd);

      } // end of if

}  // end of process_data

void setServo(char *pin, char *val) {   

    if ((pin[0] == 'S') || (pin[0] == 's')) {
      
        byte numServo = strtol(pin+1, NULL, 10);

        byte state = atoi(val);

    switch (numServo) 
      {

      case 1:

              servo_1.write(state);
              break;
        
      case 2:

              servo_2.write(state);
              break;
      }

            
  
    }

}

void getServo(char *pin) {

  byte numServo = strtol(pin+1, NULL, 10);

  switch (numServo) 
      {

      case 1:

              Serial.println(servo_1.read()); 
              break;
        
      case 2:

              Serial.println(servo_2.read());
              break;
      }

}


void processIncomingByte (const byte inByte) {
 
  static char input_line[MAX_INPUT];
  static unsigned int input_pos = 0;

  switch (inByte)
    {

    case '\n':   // end of text
      input_line[input_pos] = 0;  // terminating null byte
      
      // terminator reached! process input_line here ...
      process_data (input_line);
      
      // reset buffer for next time
      input_pos = 0;  
      break;

    case '\r':   // discard carriage return
      break;

    default:
      // keep adding if not full ... allow for terminating null byte
      if (input_pos < (MAX_INPUT - 1))
        input_line[input_pos++] = inByte;
      break;   
      

    }  // end of switch
    
  }// end of processIncomingByte


void loop() {

// if serial data available, process it
  while (Serial.available () > 0)
    processIncomingByte (Serial.read());
  
    }

26.1.4. Estrutura Física

Montei inicialmente um protótipo usando duas chapas de acrílico de 5mm de espessura e barras roscadas de ~8mm de diâmetro. Mas tive problemas de trincas na hora de fazer os furos na chapa de acrílico.

Aproveitei este protótipo para fazer os testes iniciais, mas providenciei a montagem de outra válvula usando chapas de acrílico mais finas (3mm) e barras roscadas de ~5mm conforme a figura 327

Figura 327. Diagrama esquemático com a visão superior das respectivas posições da válvula. Na posição 1 conectando os reservatórios A e C, e na posição 2 conectando os reservatórios B e C. E a visão lateral da estrutura de suporte para o servomotor e válvula de 3 vias respectivamente nas posições 1 e 2.

Diagrama esquemático com a visão superior das respectivas posições da válvula. Na posição 1 conectando os reservatórios A e C, e na posição 2 conectando os reservatórios B e C. E a visão lateral da estrutura de suporte para o servomotor e válvula de 3 vias respectivamente nas posições 1 e 2.

Tinha comprado servomotores da marca MG995 e MG996R. E após consultar o site do fabricante escolhi o modelo MG996R com a promessa de maior precisão.

26.1.5. Interface Gráfica

Para a comunicação com a placa Arduino foi feita uma interface gráfica em Tcl/Tk:

#!/usr/bin/env wish


#Interface to control a 3 way valve with a servomotor

set fonte_grande {Times 18}

#Info message
label .msg -text "Interface para controle de válvula de 3 vias" -font $fonte_grande 

pack .msg -side top -pady 10

#Main frame
frame .frame_control

pack .frame_control -side bottom

#Frames to each position
labelframe .frame_control.frame_pos_1

labelframe .frame_control.frame_pos_2

labelframe .frame_control.frame_pos_3

pack .frame_control.frame_pos_1 .frame_control.frame_pos_2 .frame_control.frame_pos_3 \
    -side left -ipady 5

#Create links to labels
image create photo position_1 -format GIF -file Posicao_01.gif

label .frame_control.frame_pos_1.image_position_1 -image position_1

image create photo position_2 -format GIF -file Posicao_02.gif

label .frame_control.frame_pos_2.image_position_2 -image position_2

image create photo position_3 -format GIF -file Posicao_03.gif

label .frame_control.frame_pos_3.image_position_3 -image position_3

pack .frame_control.frame_pos_1.image_position_1 \
    .frame_control.frame_pos_2.image_position_2 \
    .frame_control.frame_pos_3.image_position_3 \
    -side top -pady 10 -padx 10 

radiobutton .frame_control.frame_pos_1.pos_1 -text "Posição 1" -font $fonte_grande \
    -variable position -value 1 \
    -relief flat -indicatoron 0 \
    -command {
	puts "Posição $position"
	puts $porta "SET_SERVO;S1;0"
    }

radiobutton .frame_control.frame_pos_2.pos_2 -text "Posição 2" -font $fonte_grande \
    -variable position -value 2 \
    -relief flat -indicatoron 0 \
    -command {
	puts "Posição $position"
	puts $porta "SET_SERVO;S1;86"
    }

radiobutton .frame_control.frame_pos_3.pos_3 -text "Posição 3" -font $fonte_grande \
    -variable position -value 3 \
    -relief flat -indicatoron 0 \
    -command {
	puts "Posição $position"
	puts $porta "SET_SERVO;S1;40"
    }

pack .frame_control.frame_pos_1.pos_1 .frame_control.frame_pos_2.pos_2 .frame_control.frame_pos_3.pos_3


set porta [ open /dev/ttyACM0 r+ ]

fconfigure $porta -mode 9600,n,8,1 -buffering none

É uma interface básica (Figura 328) apenas para testar o envio de comandos para a placa Arduino. Mas pode ser complementada com recursos para a programação de scripts para automatizar a operação de 1 ou mais válvulas.

Figura 328. Interface gráfica para o controle da válvula através da placa Arduino.

Interface gráfica para o controle da válvula através da placa Arduino.

26.2. Protótipos Alternativos

Para reduzir o espaço ocupado pelo conjunto motor+válvula e ter uma estrutura mais fácil de montar e acomodar dentro de um sistema maior, providenciei a montagem de um novo protótipo.

A figura 329 mostra os 3 protótipos que foram montados.

Figura 329. Os 3 protótipos que foram montados para encontrar a melhor forma de conectar o servomotor com a válvula de 3 vias.

Os 3 protótipos que foram montados para encontrar a melhor forma de conectar o servomotor com a válvula de 3 vias.

A figura 330 mostra as etapas de montagem e detalhes do terceiro protótipo.

Figura 330. Etapas de montagem e detalhes do terceiro protótipo.

Etapas de montagem e detalhes do terceiro protótipo.

O uso da parte superior de uma seringa de 5mL para fazer a conexão entre o servomotor e a válvula se mostrou mais simples de montar e mais compacta do que o tubo de PVC, como mostra a figura 331.

Figura 331. Etapas de montagem do conector entre a válvula e o servomotor usando a parte superior de uma sering de 5mL.

Etapas de montagem do conector entre a válvula e o servomotor usando a parte superior de uma sering de 5mL.

Em seguida o conector é parafusado na hélice do servomotor como mostra a figura 332.

Figura 332. Fixação do conector à hélice do servomotor.

Fixação do conector à “hélice” do servomotor.

Para manter o corpo da válvula e o servomotor ainhados foi montada uma estrutura com 2 placas de acrílico de 3 mm de espessura, e 4 barras roscadas de ~5mm de diâmetro conforme a figura 333.

Figura 333. Etapas de montagem das estruturas de acrílico para o alinhamento da válvula com o servomotor.

Etapas de montagem das estruturas de acrílico para o alinhamento da válvula com o servomotor.

26.3. Calibração

Para o controle adequado da válvula é necessário identificar os ângulos do servomotor correspondentes às posições desejadas. E para fazer essa calibração implementamos uma interface gráfica usando o widget scale como mostra a figura 334.

Figura 334. Interface gráfica do programa para calibração de um servo motor

Interface gráfica do programa para calibração de um servo motor

Também fizemos modificações no Sketch do Arduino para o envio de diversos comandos para a placa Arduino.

Essa abordagem está documentada na seção Arduino Multicomando.

Para fazer a calibração precisamos identificar as posições de 0° e 180° do eixo do servo e posicionar a hélice e a torneira nas posições desejadas respeitando os limites do eixo e o sentido de rotação do servomotor.

Em seguida fazemos deslocamentos sucessivos com o programa de calibração avaliando visualmente quais os ângulos que correspondem às conexões desejadas.

Nota

É difícil explicar esse procedimento com palavras. Você só vai entender fazendo. :-)

26.4. Links Interessantes