En la entrada anterior del curso hemos visto cómo utilizar el monitor serie para controlar el color de un LED RGB, y hoy vamos a aprender cómo controlar servos (o servo motores) con la ayuda de un potenciómetro. Con esto podremos aprender, por ejemplo, a orientar un determinado sensor para que obtenga información de una zona específica.
Para ello, veremos un par de conceptos nuevos, la lectura analógica y la función map, pero explicaremos ambas después.
Lista de materiales
- Zum Core, placa Arduino o Compatible.
- Servo.
- Potenciómetro.
Conexiones eléctricas
Conectar los módulos para este proyecto es muy fácil, ya que sólo tenemos que conectar el servo a un pin con salida PWM y el potenciómetro a una entrada analógica. Puedes ver un esquema de conexión en la imagen siguiente:
El código
Vamos a empezar por el ejemplo más sencillo para luego complicarlo un poco.
Moviendo el servo a la posición indicada por el potenciómetro
Vamos a escribir primero el código completo para posteriormente analizarlo parte por parte.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include int pinPot = A1; //Pin Analógico al que está conectado el potenciómetro Servo miServo; //variable para controlar el servo void setup() { miServo.attach(10); } void loop() { int potRead = analogRead(pinPot); // lee el valor del sensor analógico int servoValue = map(potRead, 0, 1023, 0, 180); //transforma el valor entre 0 y 1023 a 0 y 180 miServo.write(servoValue); //manda el servo al ángulo correspondiente delay(500); //espera 500 ms } |
Empezamos incluyendo la librería Servo y declarando las variables de los pines:
1 2 3 4 5 6 |
//Incluimos la libreria Servo #include //Creamos un objeto servo Servo miServo; int pinPot = A1; //Pin Analógico al que está conectado el potenciómetro |
La librería Servo es especifica para este tipo de motores. La mayoría de los servos permiten movimiento entre 0 y 180º. Si quieres conocer más sobre la librería Servo puedes consultar la página de referencia de arduino.
Función setup()
1 2 3 4 |
void setup() { miServo.attach(10); } |
En esta función indicamos que el servo está conectado en el pin digital 10.
Función loop()
En esta función es dónde debemos realizar la tarea. Debemos seguir los siguientes pasos.
- Leemos el valor del potenciómetro, al ser una entrada analógica dará un valor entre 0 y 1023. Usamos la función analogRead()
- Transformamos el valor entre 0 y 1023 en un valor entre 0 y 180, para ello usamos la función map(). La función map convierte una variable desde el rango de origen al rango de destino, es decir, una variable que está en un intervalo A-B pasará a un intervalo C-D manteniendo la posición relativa del rango de origen al rango de destino. Podéis conocer más sobre map en la página de referencia.
- Comandamos al servo para que vaya a la posición obtenida entre 0 y 180.
- Detenemos la ejecución durante 500 ms. La razón de esto es que no queremos que el servo esté continuamente cambiando de posición, esto hace que nuestro programa sea menos reactivo, pero más estable
Este es el código:
1 2 3 4 5 6 7 8 |
void loop() { int potRead = analogRead(pinPot); // lee el valor del sensor analógico int servoValue = map(potRead, 0, 1023, 0, 180); //transforma el valor entre 0 y 1023 a 0 y 180 miServo.write(servoValue); //manda el servo al ángulo correspondiente delay(500); //espera 500 ms } |
Moviendo el servo a la posición indicada por el potenciómetro sin saltos bruscos
En el siguiente ejemplo vamos a realizar la misma tarea, pero forzando al servo a avanzar en pequeños pasos de 1 grado cada 10 milisegundos. De este modo evitamos saltos groseros resultado de movimientos bruscos del potenciómetro.
Tras la declaración inicial:
1 2 3 4 5 6 |
//Incluimos la libreria Servo #include //Creamos un objeto servo Servo miServo; int pinPot = A1; //Pin Analógico al que está conectado el potenciómetro |
Después declaramos las variables que necesitaremos para la correcta ejecución del programa:
1 |
int aktValue, nextValue; // Variable en la que almacenamos los valores del potenciómetro |
A continuación utilizamos la función setup para inicializar el programa:
1 2 3 4 5 6 7 8 |
void setup() { //Iniciamos la librería Serial para comunicarnos con la placa Serial.begin(9600); pinMode(pinPot, INPUT); miServo.attach(10); //Indica en que pin está conectado el servo Serial.println("¡Listo!"); } |
En la función setup iniciamos la librería Serial, marcamos el pin del potenciómetro como entrada e indicamos al programa en qué pin está conectado el servo. Además, mandamos un mensaje que indica al usuario que el programa está listo para funcionar.
A continuación podemos ver la función loop al 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 33 |
void loop() { nextValue = analogRead(pinPot); // Leemos el valor del potenciómetro (entre 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Escalamos a un valor que el servo puede entender (0-180) //imprimimos el valor en grados de la posición del servo Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); /* Distinguimos dos casos: En el primer caso la siguiente posición es mayor que la posición actual, por lo que aumentamos el valor En el segundo caso la siguiente posición es menor que la posición actual, por lo que disminuimos el valor */ if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { miServo.write(i); //utilizamos la función especifica de la librería servo para escribir el valor delay(10); // y esperamos a que el valor llegue. } } else if (nextValue < aktValue) { for (int i = aktValue; i >= nextValue; i--) { miServo.write(i); delay(10); } } aktValue = miServo.read(); delay(1000); } |
Dentro de la función loop, en primer lugar, tomamos medidas del potenciómetro y utilizamos la función map para “traducir” la lectura del potenciómetro a un ángulo, y después imprimimos en el monitor serie la información del ángulo:
1 2 3 4 5 6 7 |
nextValue = analogRead(pinPot); // Leemos el valor del potenciómetro (entre 0-1023) nextValue = map(nextValue, 0, 1023, 0, 180); // Escalamos a un valor que el servo puede entender (0-180) //imprimimos el valor en grados de la posición del servo Serial.print("Ángulo = "); Serial.print(nextValue); Serial.println("º"); |
La lectura analógica permite distinguir los valores comprendidos entre 0 y 5 V, al contrario que la lectura digital. Las placas ZUM y Arduino, por lo general, incorporan un conversor analógico-digital de 10 bits, por lo que el rango que podemos obtener es 0-1023. Podéis conocer más sobre analogRead en la página de referencia.
Después pasamos a modificar la posición del servo, para lo que distinguimos dos casos:
- El valor al que se moverá el servo es mayor que el actual, por lo que tenemos que aumentar la posición:
1 2 3 4 5 6 |
if (nextValue > aktValue) { for (int i = aktValue; i <= nextValue; i++) { miServo.write(i); //utilizamos la función especifica de la librería servo para escribir el valor delay(10); // y esperamos a que el servo llegue al valor. } } |
- El valor al que se moverá el servo es menor que el actual, por lo que tenemos que disminuir la posición:
1 2 3 4 5 6 |
else if (nextValue < aktValue) { for (int i = aktValue; i > nextValue; i--) { miServo.write(i); delay(10); } } |
Por último guardamos el valor de posición que tiene el servo y pausamos la ejecución del programa durante un segundo:
1 2 |
aktValue = miServo.read(); delay(1000); |