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)

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.
Para entender o funcionamento dessas válvulas vamos representar uma “Torneira de 3 Vias” por um diagrama esquemático como mostra a figura 321.
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.

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.

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)
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.
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.
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)

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áximo’120°”.
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”.
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) | 0° |
| 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
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());
}
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.

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.
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.
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.

A figura 330 mostra as 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.

Em seguida o conector é parafusado na “hélice” do servomotor como mostra a figura 332.
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.

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.
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.
É difícil explicar esse procedimento com “palavras”. Você só vai entender “fazendo”. :-)