Joystick Controlando 2 Microservomotores
O objetivo desse projeto é controlar dois microservomotores com um joystick. Vamos implementar duas abordagens de controle que serão apresentadas em dois diferentes sketches. O microservo SG90, usado nesse projeto, pode girar 180 graus, sendo 90 graus em cada direção. O SG90 pesa apenas 9 gramas, funciona com tensões de alimentação na faixa de 3.0 â 6,0 Volts, tendo as seguintes dimensões: 32 x 30 x 12 mm.
Figura 1: Microservomotor SG90
Por sua vez, o joystick trabalha com potenciômetros para definir o deslocamento dos eixos X e Y, e uma chave push button.
Figura 2: Módulo Joystick
PInagem do Modulo Joystick:
GND: GND (terra)
Vcc: 3,3 – 5 Volts
VRx: Saída Analógica Eixo X (potenciômetro)
VRy: Saída Analógica Eixo Y (potenciômetro)
SW: Saída Digital do push button (contato seco do botão)
Em nosso projeto, o pino VRx do joystick foi conectado a porta analógica 4 do Arduino e o pino VRy do joystick foi conectado a porta analógica 5 do Arduino. A saída digital SW não foi usada nesse exemplo. Operando em vazio (sem carga) o SG90 pode ser alimentado pela fonte do Arduino. Todavia, quando o microservo estiver operando em carga deverá ser utilizada uma fonte de alimentação externa.
Figura 3: Exemplo de Fonte Externa de + 5 Volts/500mA
Para fins de identificação um dos microservomotores de nosso projeto será chamado de base e o outro de inclinação. Esses nomes foram dados de propósito, uma vez que esse projeto simula a operação de um braço robô, como o ilustrado na figura 4.
Figura 4: Exemplo de Braço Robô com Microservomotores
Em cada microservo o terminal vermelho foi conectado ao Vcc, provido por uma fonte externa, e o terminal marrom foi conectado ao GND dessa mesma fonte externa. O terminal laranja do microservo base foi conectado à porta digital 7 do Arduino. Por sua vez, o terminal laranja do microservo inclinação foi conectado à porta digital 8 do Arduino.
Figura 5: Joystick controlando 2 microservomotores SG90
Nosso projeto usa a biblioteca <VarSpeedServo.h> contendo funções para controle de servomotores, com destaque para as seguintes:
Tabela 1: Funções da Biblioteca <VarSpeedServo.h>
Note que na função write(value, speed), para ajustar a velocidade do servomotor para a velocidade máxima o valor de speed deve ser igual a zero, por definição da biblioteca. Depois existe uma escala crescente de 1 a 255, havendo, portanto, 256 valores de velocidade. Se o valor de speed é igual a 255, a velocidade será ainda muito alta, equivalente a 255/256 ou 0,996 (99,6% da velocidade máxima). Se o valor do speed é igual a 60, a velocidade será baixa, equivalente a 60/256 ou 0,234 (ou 23,4% da velocidade máxima).
Montagem no Protoboard
Figura 6: Joystick controlando 2 microservomotores
AGORA, monte o seu projeto com cuidado e atenção e veja como tudo isso funciona analisando os sketchs abaixo!!!
Cenário 1: Sketch usando a função map()
**********
//JoyStick controla 2 servomotores #include <VarSpeedServo.h> //Cria objeto para controlar o servo base VarSpeedServo servo_base; //Cria objeto para controlar o servo inclinacao VarSpeedServo servo_inclinacao; int pino_x = A4; //Pino ligado ao X do joystick int pino_y = A5; //Pino ligado ao Y do joystick int val_x; //Armazena o valor do eixo X int val_y; //Armazena o valor do eixo Y void setup() { //Define a porta a ser ligada ao servo base servo_base.attach(7); //Define a porta a ser ligada ao servo inclinacao servo_inclinacao.attach(8); } void loop() { //Recebe o valor do joystick, eixo X val_x = analogRead(pino_x); //Converte o valor lido para um valor entre 1 e 180 graus val_x = map(val_x, 0, 1023, 1, 180); //Move o servo base para a posicao definida pelo joystick servo_base.slowmove(val_x, 60); //Recebe o valor do joystick, eixo Y val_y = analogRead(pino_y); //Converte o valor lido para um valor entre 1 e 180 graus val_y = map(val_y, 0, 1023, 1, 180); //Move o servo inclinacao para a posicao definida pelo joystick servo_inclinacao.slowmove(val_y, 60); //Aguarda a movimentacao do servo e reinicia a leitura delay(30); }**********
Cenário 2: Sketch usando a função if()
**********
// Joystick controla 2 servo motores #include <VarSpeedServo.h> /* * servo1 - Servo da base - Porta digital 7 * servo2 - Servo de inclinacao - Porta digital 8 * */ VarSpeedServo servo1; VarSpeedServo servo2; /* * Definicao das entradas analogicas do Joytick * VRx = A4 * VRy = A5 */ int potpin1 = A4; int potpin2 = A5; int val1; int val2; /* * Define os valores iniciais de posição de cada servo */ static int s1 = 70; static int s2 = 110; void setup() { Serial.begin(9600); // configura os servos de acordo com a definicao acima servo1.attach(7); // base, pino digital 7 servo2.attach(8); // extensao, pino digital 8 // move todo o braco para posicao inicial servo1.write(70);// base servo2.write(110);// inclinacao } void loop() { // Controle do servo da base val1 = analogRead(potpin1); if (val1 &amp;amp;amp;amp;lt; 100) { s1 = s1 - 2; if (s1 &amp;amp;amp;amp;lt;= 10) { s1 = 10; } servo1.write(s1); delay(50); } if (val1 &amp;amp;amp;amp;gt; 900) { s1 = s1 + 2; if (s1 &amp;amp;amp;amp;gt;= 170) { s1 = 170; } servo1.write(s1); delay(50); } // Controle do servo da inclinacao val2 = analogRead(potpin2); if (val2 &amp;amp;amp;amp;gt; 900) { s2 = s2 - 2; if (s2 &amp;amp;amp;amp;lt;= 10) { s2 = 10; } servo2.write(s2); delay(50); } if (val2 &amp;amp;amp;amp;lt; 100) { s2 = s2 + 2; if (s2 &amp;amp;amp;amp;gt;= 170) { s2 = 170; } servo2.write(s2); delay(50); } // exibe os valores analogicos na tela Serial.print(val1); Serial.print(" : "); Serial.print(val2); Serial.print(" : "); Serial.println(); }**********
Observações sobre o Código
Cenário 1: Sketch usando a função map()
Esse sketch usa a biblioteca <VarSpeedServo.h> que é inclusa no código na parte inicial, antes do void setup(). São criados os objetos para controlar o servo motor da base e o servo motor da inclinação através de VarSpeedServo servo_base e VarSpeedServo servo_inclinacao.
O comando int pino_x = A4 estabelece que o pino analógico A4 está ligado ao potenciômetro do eixo x do joystick. Por sua vez, o comando int pino_y = A5; estabelece que o pino analógico A5 está ligado ao potenciômetro do eixo y do joystick. Os valores lidos no potenciômetro do eixo x do joystick serão armazenados na variável inteira val_x, e os valores lidos no potenciômetro do eixo y do joystick serão armazenados na variável inteira val_y. Considerando que o conversor A/D do Arduino tem 10 bits, a leitura de cada potenciômetro do joystick varia de 0 à 1023.
Na função setup(), os comandos servo_base.attach(7) e servo_inclinacao.attach(8) são usados para ligar o servo motor da base ao pino digital 7 e o servo motor da inclinação ao pino digital 8.
A função loop() do sketch usa a função map() como elemento de controle. Em primeiro lugar é lido o valor do potenciômetro do eixo x através do comando val_x = analogRead(pino_x), lembrando que pino_x é a entrada analógica A4 do Arduino. O valor de val_x varia de 0 à 1023. Todavia, o servo motor, quando gira, deve ser controlado por um valor que representa um ângulo que varia de 0 à 179 graus. Por conta disso, é feita a conversão do valor de 0 à 1023 para 0 à 180, através do comando val_x = map(val_x, 0, 1023, 1, 180). Em outras palavras, o valor de val_x representa um ângulo após a conversão realizada na função map().
Na instrução seguinte – servo_base.slowmove(val_x, 60); – é também usada uma das funções da biblioteca <VarSpeedServo.h> que move o servo motor da base para a posição definida por val_x em uma velocidade baixa (ajustada pelo valor 60). As linhas seguintes do sketch usam a mesma estrutura de comandos para o eixo y do joystick e o servo motor inclinação. Finalmente, o programa aguarda por 30 microsegundos – delay (30) – e reinicia a leitura.
Cenário 2: Sketch usando a função if()
Este sketch usa a biblioteca VarSpeedServo() como já explicado no exemplo anterior. Além disso, as ligações dos servomotores e do joystick no Arduino são exatamente as mesmas apresentadas na figura 6. A mudança nesse sketch é o uso da função if() ao invés da função map().
No início do sketch são criados os objetos para controlar o servo motor da base (servo1 – servo da base – porta digital 7) e o servo motor da inclinação (servo2 – servo de inclinação – porta digital 8) através de VarSpeedServo servo1 e VarSpeedServo servo2.
O comando int potpin1 = A4 estabelece que o pino analógico A4 está ligado ao potenciômetro do eixo x do joystick (VRx). Por sua vez, o comando int potpin2 = A5; estabelece que o pino analógico A5 está ligado ao potenciômetro do eixo y do joystick (VRy). Os valores lidos no potenciômetro do eixo x do joystick serão armazenados na variável inteira val1, e os valores lidos no potenciômetro do eixo y do joystick serão armazenados na variável inteira val2. As instruções abaixo definem os valores iniciais de posição de cada servo motor.
static int s1 = 70;
static int s2 = 110;
Na função setup() os comandos servo_base.attach(7) e servo_inclinacao.attach(8) são usados para ligar o servo motor da base ao pino digital 7 e o servo motor da inclinação ao pino digital 8. Em seguida, há instruções para mover os servos para a posição inicial. servo1.write(70);// base
servo2.write(110);// inclinacao
Na função loop() o código de controle de cada servo motor é separado em duas partes. Assim sendo, para cada servo motor há uma parte do código que considera que o operador move o joystick totalmente para uma de suas extremidades, e a outra parte considera que o operador move o joystick totalmente para a extremidade oposta. Com isso, o valor de resistência do potenciômetro de um determinado eixo do joystick poderá variar do centro para seu valor máximo ou, no outro sentido, do centro para o seu valor mínimo.
Figura 7: Correspondência entre a resistência do potenciômetro do joystick, a leitura na entrada analógica do Arduino e o incremento no ângulo da posição do servo motor.
No controle do servo da base a primeira instrução lê o valor do pino potpin1, que é a entrada analógica A4, onde está ligado o potenciômetro do eixo x do joystick (VRx), e o resultado dessa leitura é colocado na variável val1.
Note que quando o potenciômetro está solto, na sua posição central, o valor da leitura do pino analógico A4 é igual a 512. Quando o potenciômetro é levado para uma das extremidades, o valor da leitura do pino analógico A4 é igual a zero (ou próximo de zero). Quando o potenciômetro é levado para a extremidade oposta, o valor da leitura do pino analógico A4 é igual a 1023.
Vamos supor que o operador está movendo a alavanca do joystick para o lado que leva a resistência para o seu valor mínimo (próximo de zero ohm). O operador coloca a alavanca no mínimo e mantem a alavanca nessa posição (segurando a alavanca) até que o servo motor alcance a posição desejada. Os próximos passos do sketch mostrarão como isso acontece.
A leitura de A4 será um valor baixo, próximo de zero. O sketch usa 100 como valor de comparação mínima. Nessa situação, o val1 é menor do 100.
val1 = analogRead(potpin1);
if (val1 < 100)
{
s1 = s1 – 2;
if (s1 <= 10)
{
s1 = 10;
}
servo1.write(s1);
delay(50);
}
A variável usada para posicionar o servo1 (servo motor da base) é s1. O valor inicial de s1 é 70. Como a condição da função if() é verdadeira (val1 é menor do que 100), será feito o decremento de 2 unidades de s1 (s1=s1-2). O valor 2 desse decremento foi escolhido por tentativa e erro. Recomenda-se que sejam testados outros valores de decremento para embasar a escolha final a ser implementada no sketch.
Na primeira rodada do loop() o s1 ficará igual a 68 (=70-2). A próxima instrução é um if() que pergunta se o s1 atingiu o valor 10 (que é o ângulo mínimo considerado no skecth). Nessa primeira rodada do loop() isso ainda não ocorreu, pois s1 é igual a 68. Então, a condição dentro das chaves desse if() não é executada.
Com a instrução servo1.write(s1) o servo motor da base se move 2 graus em uma direção e há uma espera de 50 milisegundos.
O programa prossegue com if (val1 > 900), onde 900 é um valor de comparação usado quando o operador move a alavanca do joystick para o lado oposto (máxima resistência do potenciômetro). O resultado desse if() não será verdadeiro, uma vez que o operador ainda está segurando a alavanca do joystick para o lado que leva para a mínima resistência do potenciômetro. Afinal de contas, val1 não pode ser menor do que 100 e, ao mesmo tempo, maior do que 900.
if (val1 > 900)
{
s1 = s1 + 2;
if (s1 >= 170)
{
s1 = 170;
}
servo1.write(s1);
delay(50);
}
Isso faz com que nenhum dos comandos dentro das chaves desse if() sejam executados, levando o programa para o código que controla o servo motor da inclinação, que veremos mais adiante. Como essa parte do código não afeta o controle do servo motor da base, do ponto de vista deste, ocorre apenas um tempo de espera equivalente ao tempo requerido para a execução das instruções de controle do servo motor da inclinação. O sketch então continua com as instruções de exibição de valores analógicos na tela do computador PC, via Serial.print(), e volta para executar o segundo loop().
Note que o operador ainda está segurando a alavanca do joystick na posição que leva a resistência do potenciômetro para o seu valor mínimo (próximo de zero ohm). Como a condição da função if() é verdadeira (val1 é menor do que 100), será feito o decremento de 2 unidades de s1 (s1=s1-2), resultando em s1 igual a 66 (=68-2). Novamente val 1 não será maior que 900, já que é menor que 100. Isso faz com que o servo1 se mova mais 2 graus (servo1.write(s1)). De fato, os decrementos de 2 irão ocorrer a cada rodada do loop() até que a posição desejada pelo operador seja alcançada pelo servo motor. Em outras palavras, quando visualmente o operador estiver satisfeito com a posição do servo motor que estiver controlando, ele soltará a alavanca do joystick interrompendo esses decrementos.
Embora a posição do servo motor possa variar entre zero e 180 graus, como definido no sketch, o ângulo mínimo de posição do servo motor é 10 graus e o ângulo máximo é 170 graus.
Quanto ao código que controla o servo motor da inclinação, podemos verificar que é muito semelhante ao que controla o servo motor da base, tendo as seguintes principais diferenças:
- Ao invés de val1 e s1, usa as variáveis val2 e s2;
- Interroga primeiro se o potenciômetro está sendo movido para o lado de resistência mais alta (val2 > 900) e depois se o potenciômetro está sendo movido para o lado de resistência mais baixa (val2 < 100);
- As decisões de incrementar de 2 ou decrementar de 2 são diferentes para os pares VRx-servo1 e VRy-servo2 (tabela DDD).
Tabela 2: Decisões de incrementar e decrementar usadas para os servo motores da base e da inclinação
Isso possibilita a escolha do sentido de movimento do servo motor em relação a direção do movimento da alavanca do joystick. Como sugerido anteriormente, alguns testes práticos serão úteis para embasar a escolha final a ser implementada no sketch.
Esperamos que você tenha aproveitado e explorado as possibilidades discutidas em nosso artigo. Como sempre, convidamos você a nos enviar suas perguntas e questionamentos. É isso aí, até a próxima!

Haroldo Mamede Coutinho Simões
Engenheiro de telecomunicações e pós-graduado em gerenciamento de negócios, tendo trabalhado em empresas de médio e grande porte por mais de 30 anos, atuando em diferentes projetos e departamentos. É instrutor de treinamento, tendo ministrado workshops em várias empresas, professor universitário em cursos MBA presenciais e tutor de cursos à distância. É apaixonado por tecnologia, especialmente pela plataforma Arduino e tudo de positivo que ela pode fazer pelas pessoas quando dela se aproximam.
VEJA TAMBÉM
Regador automático de plantas com Arduino
Aprenda neste artigo, como automatizar a rega de suas plantas, utilizando o Arduino NANO. Este projeto, além do baixo custo, pode ser montado em menos de uma hora e irá garantir que as suas plantas sempre tenham água disponível, garantido um crescimento adequado e...
Datalogger com cartão SD. Registre: temperatura, umidade, luminosidade e tensão)
Neste post, vamos aprender a como montar datalogger, para registrar em um cartão SD, temperatura, umidade relativa, tensão e nível de luminosidade. Esse tipo de dispositivo é extremamente útil para fazer análises de fenômenos que dependem do tempo. Por exemplo,...
Fita de LEDs RGB endereçáveis WS2812B e a biblioteca fastLED
No post de hoje, vamos conhecer a fita de LEDs WS2812B endereçáveis e como utilizá-la com o Arduino UNO. Essa fita de LEDs se destaca, em relação as outras do mercado, pelo fato de que seus LEDs podem ser controlados de maneira individual, permitindo que o...
NEWSLETTER
Assine nossa newsletter e receba as novidades.
0 comentários