Na entrada anterior deste curso, vimos como utilizar o monitor série para controlar a cor de um LED RGB. Agora vamos aprender como controlar servos (ou servo motores) com a ajuda de um potenciómetro. Com isto poderemos aprender, por exemplo, a orientar um determinado sensor para que obtenha informação de uma zona específica. Para isso, vamos conhecer dois conceitos novos: a leitura analógica e a função map. Explicaremos ambas depois.
Lista de materiais
- ZUM BT-328, placa Arduino ou compatível.
- Um servo
- Um potenciómetro.
Conexões eléctricas
Conectar os módulos para este projecto é muito fácil, porque só temos que conectar o servo a um pino com saída PWM e o potenciómetro a uma entrada analógica. Podes ver o esquema de conexão na imagem seguinte:
O código
Vamos começar por um exemplo simples … mas iremos complicá-lo um pouco, logo a seguir!
Mover o servo para a posição indicada pelo potenciómetro
Vamos escrever primeiro o código completo, para posteriormente analisá-lo passo a passo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include int pinPot = A1; // Pino analógico onde está conectado o potenciómetro Servo meuServo; // variável para controlar o servo void setup() { meuServo.attach(10); } void loop() { int potRead = analogRead(pinPot); // lê o valor do sensor analógico int servoValue = map(potRead, 0, 1023, 0, 180); //transforma o valor entre 0 e 1023, para 0 e 180 meuServo.write(servoValue); //manda o servo para o ângulo correspondente delay(500); //espera 500 ms } |
Começamos por incluir a biblioteca Servo e por declarar as variável dos pinos:
1 2 3 4 5 6 |
// Incluímos a biblioteca <em>Servo</em> #include // Criamos o objecto <em>Servo</em> Servo meuServo; int pinPot = A1; // Pino analógico onde está conectado o potenciómetro |
A biblioteca Servo é específica para este tipo de motores. A maioria dos servos permitem um movimento entre 0 e 180º. Se quiseres conhecer mais sobre a biblioteca Servo, podes consultar a página de referência do Arduino.
Função setup()
1 2 3 4 |
void setup() { meuServo.attach(10); } |
Nesta função, indicamos que o servo está conectado no pino digital 10.
Função loop()
Nesta função é onde devemos realizar a tarefa. Devemos seguir os seguintes passos.
- Lemos o valor do potenciómetro. Por ser uma entrada analógica, irá devolver um valor entre 0 e 1023. Usamos a função analogRead()
- Transformamos o valor entre 0 e 1023, num valor entre 0 e 180. Para isso usamos a função map(). Esta função converte uma variável do seu intervalo original, para um intervalo de destino, ou seja, uma variável que esteja num intervalo A-B passará a um intervalo C-D, mantendo a posição relativa do intervalo de origem, no intervalo de destino. Podes saber mais sobre a função map na sua página de referência.
- Comandamos o servo para que vá para a posição obtida entre 0 e 180.
- Paramos a execução durante 500 ms. A razão para isto é não querermos que o servo esteja continuamente a alterar de posição. Isto faz com que o nosso programa seja menos reactivo, mas mais estável.
Este é o código:
1 2 3 4 5 6 7 8 |
void loop() { int potRead = analogRead(pinPot); // lê o valor do sensor analógico int servoValue = map(potRead, 0, 1023, 0, 180); // transforma o valor entre 0 e 1023, para 0 e 180 meuServo.write(servoValue); // envia o servo para o ângulo correspondente delay(500); // espera 500 ms } |
Mover o servo até à posição indicada pelo potenciómetro, sem saltos bruscos
No exemplo seguinte, vamos realizar a mesma tarefa, mas forçando o servo a avançar em pequenos passos de 1 grau cada 10 milissegundos. Deste modo evitamos saltos grosseiros, que são resultado de movimentos bruscos do potenciómetro. Depois da declaração inicial:
1 2 3 4 5 6 |
//Incluímos a biblioteca <em>Servo</em> #include // Criamos o objecto <em>Servo</em> Servo meuServo; int pinPot = A1; // Pino analógico onde está conectado o potenciómetro |
Depois declaramos as variáveis que vamos necessitar para a execução correcta do programa:
1 |
int aktValue, nextValue; // Variável onde armazenamos os valores do potenciómetro |
A seguir, utilizamos a função setup para inicializar o programa:
1 2 3 4 5 6 7 |
void setup() { //Iniciamos a biblioteca <em>Serial</em> para comunicarmos com a placa Serial.begin(9600); pinMode(pinPot, INPUT); meuServo.attach(10); // Indica em que pino está conectado o servo Serial.println("Pronto!"); } |
Na função setup, iniciamos a biblioteca Serial, marcamos o pino do potenciómetro como entrada e indicamos ao programa em que pino está conectado o servo. Enviamos também uma mensagem que indica ao utilizador que o programa está pronto para funcionar. A seguir podemos ver a função loop por completo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
void loop() { nextValue = analogRead(pinPot); // Lemos o valor do potenciómetro (entre 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Convertemos para um valor que o servo possa entender (0-180) // imprimimos o valor em graus, da posição do servo Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); /* Distinguimos dois casos: No primeiro caso, a posição seguinte é maior que a posição actual, e por isso aumentamos o valor No segundo caso, a posição seguinte é menor que a posição actual, e por isso diminuímos o valor */ if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { meuServo.write(i); // utilizamos a função especifica da biblioteca <em>Servo</em> para escrever o valor delay(10); // e esperamos até o valor chegar. } } else if (nextValue < aktValue) { for (int i = aktValue; i >= nextValue; i--) { meuServo.write(i); delay(10); } } aktValue = meuServo.read(); delay(1000); } |
Dentro da função loop, em primeiro lugar, tiramos as medidas do potenciómetro e utilizamos a função map para “traduzir” os valores do potenciómetro para um ângulo, e depois imprimimos no monitor série, a informação do ângulo:
1 2 3 4 5 6 7 |
nextValue = analogRead(pinPot); // Lemos o valor do potenciómetro (entre 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Convertemos para um valor que o servo possa entender (0-180) // imprimimos o valor em graus, da posição do servo Serial.print("Ângulo = "); Serial.print(nextValue); Serial.println("<sup><span style="font-size: 13.3333px; line-height: 20px;">o</span></sup>"); |
A leitura analógica permite distinguir os valores compreendidos entre 0 e 5 V, ao contrário da leitura digital. As placas ZUM e Arduino, geralmente, possuem um conversor analógico-digital de 10 bits, o que significa que podemos obter um intervalo entre 0 e 1023. Podes saber mais sobre analogRead na página de referência. Seguidamente, vamos modificar a posição do servo, para que possamos distinguir entre dois casos:
- O valor que o servo se vai mover, é maior que o actual, e por isso temos que aumentar a posição:
1 2 3 4 5 6 |
if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { meuServo.write(i); // utilizamos a função específica da biblioteca <em>Servo</em> para escrever o valor delay(10); // e esperamos até que o servo chegue a esse valor. } } |
- O valor que o servo se vai mover, é menor que o actual, e por isso temos que diminuir a posição:
1 2 3 4 5 6 |
else if (nextValue < aktValue) { for (int i = aktValue; i > nextValue; i--) { meuServo.write(i); delay(10); } } |
Por último guardamos o valor da posição que tem o servo, e pausamos a execução do programa durante um segundo:
1 2 |
aktValue = meuServo.read(); delay(1000); |