Hoy, aprenderemos cómo usar un joystick Arduino usando sus entradas analógicas.
Si te gustan los videojuegos, seguramente has visto un joystick en un control. Hay dos tipos principales de controles: los que tienen botones y los que tienen joysticks.
El joystick es esa palanca que encuentras en algunos controles de consolas. Se usa para mover a tu personaje o navegar por los menús del juego.
Hoy, no voy a enseñarte a jugar con un control de PlayStation. En su lugar, puedes aprender a usar un joystick con Arduino, utilizando entradas analógicas.
Luego, podrás decidir si quieres crear un videojuego o controlar un brazo robótico.
Antes de eso, veremos:
- Cómo funcionan los conversores analógico-digitales y qué tipos hay.
- Las características principales de estos conversores.
- Cómo utilizar la función analogRead().
- Por último, cómo controlar un servomotor con un joystick usando Arduino UNO.
¿Qué es un ADC o convertidor analógico digital?
Antes de explicarte qué es un convertidor analógico digital es necesario que aprendas a diferenciar las señales analógicas de las digitales.
Lo importante es que comprendas que vivimos en un mundo analógico, ya que todas las señales físicas que eres capaz de percibir son analógicas:
- La temperatura.
- Los sonidos.
- Los colores.
- La iluminación.
Por otra parte, los microcontroladores son dispositivos digitales. Eso indica que no son capaces de interpretar señales analógicas.
Entonces, ¿Cómo hacer para trabajar con señales analógicas utilizando un microcontrolador?
Aquí es donde entra en acción el convertidor analógico digital (ADC, por sus siglas en inglés Analog-to-Digital Converter). Este es el encargado de “traducir” las señales del mundo analógico al mundo digital.
Esto permite realizar proyectos donde tu Arduino o tu ESP es capaz de procesar variables físicas como la temperatura o la iluminación. Puede ser para encender las luces del jardín por la noche, manejar la temperatura de una nevera o controlar un joystick con Arduino.
Tipos de Conversores Analógico-Digitales
Cuando se trata de convertidores analógico-digitales (ADC), hay varios tipos utilizados comúnmente:
- Paralelo (también conocidos como flash).
- Aproximaciones sucesivas.
- Convertidores paralelos.
Los convertidores de tipo paralelo son conocidos por ser los más rápidos disponibles en el mercado y su principio de funcionamiento es relativamente simple.
Estos se basan en un conjunto de resistencias dispuestas en serie para generar varios voltajes a partir de uno de referencia. Este proceso es similar a usar un divisor de voltaje, pero en lugar de una sola resistencia, se emplean varias en serie.
Funcionamiento de los Comparadores
Los comparadores tienen dos entradas marcadas como + y -, junto con una salida. Si el voltaje en la entrada + es mayor que el de la entrada -, la salida estará en estado alto (HIGH). De lo contrario, la salida será baja (LOW).
En este caso, todos los pines + de los comparadores están conectados al voltaje analógico a medir (VAA). Mientras tanto, los pines – están conectados a los divisores resistivos. Así, dependiendo del voltaje en VAA, variará el número de comparadores en estado alto.
Por ejemplo, si se aplica un voltaje de 3.5 voltios en VAA, solo se activará el último comparador.
Si aplicamos un voltaje entre 3.75 y 6.25 se activarán los dos últimos y así siempre.
Consideraciones sobre la Resolución
Es importante tener en cuenta que, en este ejemplo, el convertidor considera cualquier valor entre 1.25 y 3.75 voltios como si fuera 1.25 V, debido a la baja resolución.
Para obtener resultados más precisos, se requiere emplear una mayor cantidad de resistencias y comparadores. Sin embargo, esto aumenta la complejidad y el costo de fabricación. Por ejemplo, el AD9208 es un convertidor tipo paralelo con excelentes prestaciones, pero su precio ronda los casi 2000 euros.
Estos son los convertidores más comunes y económicos, presentes en la mayoría de los microcontroladores modernos.
Su nombre se debe al método iterativo que utilizan para determinar un valor analógico. En cada paso, este algoritmo se acerca más al valor real. El proceso es el siguiente:
- Se toma el intervalo completo de voltajes que puede manejar el convertidor, por ejemplo, de 0 a 5 voltios en un Arduino UNO.
- Se compara el voltaje central del intervalo con la señal de entrada.
- Si el voltaje central es menor que la señal de entrada:
- Se toma el intervalo superior como nuevo intervalo.
- En caso contrario:
- Se toma el intervalo inferior como nuevo intervalo.
- Se vuelve al paso 2.
La figura siguiente muestra las primeras cuatro repeticiones de este proceso para una señal de entrada de 4.5 voltios en un Arduino UNO.
Obtención de Valores Analógicos
Como se puede apreciar, en el cuarto ciclo del proceso se obtiene un valor bastante cercano al valor analógico deseado. Los microcontroladores que cuentan con este tipo de conversores realizan una cantidad de iteraciones igual a su resolución, un concepto que explicaré más adelante.
Tanto los ESP8266 como la mayoría de los microcontroladores presentes en las placas Arduino vienen equipados con un convertidor analógico-digital de aproximaciones sucesivas. Esto nos permite trabajar con señales analógicas sin necesidad de añadir componentes adicionales a nuestro sistema.
Por lo tanto, se puede inferir que para manipular el joystick con Arduino uno se utiliza un convertidor de aproximaciones sucesivas.
Voltaje de Referencia en un Convertidor Analógico-Digital
El rango de entrada analógico o el voltaje de referencia determinan el intervalo de voltajes que el convertidor puede interpretar. Esto indica cuál es el máximo voltaje que se puede aplicar a las entradas analógicas.
En la mayoría de las placas Arduino, se utiliza la alimentación del microcontrolador como voltaje de referencia. Sin embargo, esto puede ser problemático cuando se utiliza una fuente de alimentación inestable, como el puerto USB de un ordenador.
Por ejemplo, en un puerto USB, el voltaje puede variar entre 4.8 y 5.3 voltios.
Para solucionar este problema, se puede utilizar la función analogReference(). Esta función permite seleccionar la referencia analógica a utilizar mediante un parámetro:
analogReference(ref);
Donde «ref» determina el tipo de referencia a utilizar y puede ser:
- DEFAULT: Utiliza la alimentación del microcontrolador como referencia, típicamente 5 V o 3.3 V.
- INTERNAL: Utiliza un voltaje interno de referencia de 1.1 V (solo disponible en placas basadas en ATmega328 como Arduino UNO).
- INTERNAL1V1: Utiliza un voltaje interno de referencia de 1.1 V (solo disponible en Arduino MEGA).
- INTERNAL2V56: Utiliza un voltaje interno de referencia de 2.56 V (solo disponible en Arduino MEGA).
- EXTERNAL: Utiliza el voltaje del pin AREF como referencia.
Es crucial que cuando se utilice el pin AREF, se le aplique un voltaje estable; de lo contrario, las mediciones realizadas serán imprecisas o erróneas.
Consideraciones sobre el Voltaje de Referencia
Es crucial que el voltaje de referencia suministrado al pin AREF sea menor que el voltaje de alimentación del microcontrolador.
Resolución de un Convertidor Analógico-Digital
La resolución de un convertidor analógico-digital se expresa en bits e indica la cantidad de niveles en los que se divide el rango de entrada analógico. Para calcular la cantidad de niveles, se eleva 2 al número de bits.
Por ejemplo, un Arduino MEGA tiene una resolución de 10 bits, lo que significa:
Esto significa que el convertidor analógico-digital devuelve un valor entre 0 y 1023, lo que representa un voltaje entre 0 y 5 voltios.
Con la resolución y el voltaje de referencia del conversor, podemos calcular la variación mínima de voltaje que se puede medir. Para ello, dividimos el rango de entrada entre 2 elevado al número de bits.
Tomando como ejemplo un Arduino UNO, con una resolución de 10 bits y un rango de 5 voltios, obtenemos:
Esto significa que no podemos medir variaciones de voltaje inferiores a 4.9 mV en una entrada analógica en un Arduino UNO.
En otro caso interesante, el ESP8266 presenta una resolución de 10 bits y un rango de tan solo 1 voltio, lo que resulta en:
En este caso, se pueden detectar variaciones de voltaje realmente pequeñas. Sin embargo, el inconveniente es que solo se pueden convertir señales con un voltaje máximo de 1 voltio.
Lamentablemente, en la mayoría de las placas basadas en ESP8266, como NodeMCU o WeMOS, su entrada analógica está conectada a un divisor resistivo. Esto nos permite medir señales de hasta 3.3 voltios, pero a expensas de una pérdida significativa de precisión. Esta pérdida de precisión se debe a que las resistencias utilizadas para el divisor resistivo no son siempre de precisión.
Por esta razón, no se recomienda utilizar el conversor analógico-digital del ESP8266 en aplicaciones que requieran una buena precisión.
En la siguiente tabla se muestra un resumen con las resoluciones y voltajes de referencia de las placas Arduino más conocidas:
PLACA | VOLTAJE DE REFERENCIA | RESOLUCIÓN |
---|---|---|
Uno | 5 V | 10 bits |
Mini, Nano | 5 V | 10 bits |
Mega, Mega2560, MegaADK | 5 V | 10 bits |
Micro | 5 V | 10 bits |
Leonardo | 5 V | 10 bits |
Zero | 3.3 V | 12 bits |
Due | 3.3 V | 12 bits |
MKR Family boards | 3.3 V | 12 bits |
ESP8266 | 1 V (3.3 V en las placas) | 10 bits |
Lectura de valores analógicos con analogRead
Realizar una conversión analógico-digital con Arduino es muy simple utilizando la función analogRead(). Por ejemplo, en el código de nuestro joystick con Arduino, puedes notar que esta función admite un único parámetro:
int D = analogRead(pin);
Donde:- pin: es el pin analógico del que se realizará la lectura.
- D: es el valor obtenido de la conversión. Este es un número entre 0 y 2^n, donde “n” es la resolución del convertidor.
El pin utilizado como parámetro tiene que ser uno de los pines analógicos de la placa Arduino. Estos pines, por lo general, están etiquetados como «Ax» en la mayoría de las placas.
A pesar de que el microcontrolador cuenta con varios pines de entrada analógicos, solo posee un convertidor analógico digital, lo que implica que no es posible realizar dos conversiones al mismo tiempo.
Por lo tanto, al implementar el joystick con Arduino, se observa que la función analogRead() internamente conecta el pin seleccionado a la entrada del convertidor, y luego inicia la conversión. Una vez terminada la conversión, retorna el valor generado por el convertidor. En total, este proceso toma cerca de 100 us.
Entonces, si planeas utilizar más de una entrada analógica, es necesario realizar una lectura primero y, al terminar, realizar la próxima; es decir, que no es posible realizar más de una lectura simultánea.
int analog1 = analogRead(A0);
int analog2 = analogRead(A5);
int analog3 = analogRead(A2);
Es importante comprender que la función analogRead() no guarda ninguna relación con analogWrite(). Incluso se puede decir que son funciones complementarias, ya que realizan operaciones inversas.
Si te interesa conocer sobre la función analogWrite(), te recomiendo dar un vistazo al artículo sobre señales PWM con Arduino y analogWrite publicado en el blog.
Antes de manejar el joystick con Arduino, veamos otro ejemplo simple que permita comprender lo analizado.
Control de iluminación con potenciómetro
En este ejemplo, te muestro cómo utilizar un potenciómetro y la función analogRead() para controlar la iluminación de un LED a partir de la posición del potenciómetro.
Para este proyecto necesitarás:
- 1x Arduino Nano *
- 1x resistencia de 330 Ω
- 1x LED
- 1x Potenciómetro
*También te sirve un Arduino MEGA o un Arduino UNO.
En las siguientes figuras puedes ver el esquema a montar.
Se ha instalado un potenciómetro rotatorio en el Arduino para variar el voltaje en el pin A2 desde 0 hasta 5 voltios.
El LED se conecta al pin digital 3 utilizando una resistencia de 330 ohmios. Se emplea este pin para poder utilizar la función analogWrite() y controlar la iluminación del LED.
Ahora vamos a analizar el código por partes.
Lo primero es declarar las constantes. En este caso, he declarado dos constantes, una con el pin del potenciómetro y otra con el pin del LED.
#define PIN_LED 3 // Conectada al led #define PIN_POT A2 // Conectada al potenciometro
La variable «raw» es utilizada para almacenar las lecturas analógicas y «out» para especificar la iluminación del LED.
void setup(){ Serial.begin(9600); pinMode( PIN_LED, OUTPUT ); }
En la función setup() se inicializa el puerto serie a una frecuencia de 9600 baudios y se configura el pin del LED como salida.
void setup() { // inicializar monitor serie a 9600 baudios Serial.begin(9600); // configurar el pin del pulsador como entrada con pullup pinMode( PIN_SW, INPUT_PULLUP ); // inicializar el servo para trabajar con el pin 6 motor.attach(PIN_SERVO); // colocar el servo en la posición de 0 grados motor.write(0); }
En la función loop() inicialmente se realiza la lectura del potenciómetro y se almacena en la variable «raw». Luego la variable «raw» es enviada al monitor serie para comprobar que todo esté funcionando bien.
void loop(){ // obtener valor analogico en el pin A2 int raw = analogRead(PIN_POT); // Enviar el valor por puerto Serie Serial.println(raw);
Como la función analogRead() retorna un valor entre 0 y 1023 es necesario adaptar el valor de «raw» a un rango entre 0 y 255 que es el empleado por la función analogWrite(). Para esto se utiliza la función map y el nuevo valor es almacenado en la variable «out».
// Ajustar el valor obtenido al rango de analogWrite out = map( raw, 0, 1023, 0, 255 );
// Ajustar la iluminacio'n del led utilizando analogWrite analogWrite( PIN_LED, out ); // esperar 50 ms delay(50); }
De manera general, el código te permite variar la intensidad del LED a partir del voltaje aplicado a un pin analógico. No necesariamente tiene que ser un potenciómetro; podría ser una LDR u otro sensor analógico.
Aquí está el código completo. Siéntete libre de modificarlo según tus necesidades.
Relación entre el voltaje y el valor del convertidor
En el ejemplo anterior, logramos obtener los valores proporcionados por el convertidor, sin embargo, no calculamos el voltaje real del pin.
Conocer el voltaje real en el pin es útil para determinar el estado de carga de una batería o trabajar con sensores analógicos, ya que estos convierten una magnitud física en un voltaje analógico.
Por ejemplo, el sensor de temperatura LM35 proporciona un voltaje de salida que varía según la temperatura. Su salida aumenta en 10 mV por cada grado Celsius de temperatura. Por lo tanto, si conocemos el voltaje de salida, podemos determinar la temperatura ambiente.
Calcular el voltaje real del pin no es complicado una vez que hemos obtenido el valor digital del convertidor. Basta con aplicar la siguiente fórmula:
Donde:
- VAN: es el voltaje analógico seleccionado.
- VREF: es el voltaje de referencia que utiliza el conversor.
- RES: resolución del convertidor analógico digital.
- D: código obtenido en la conversión.
Para un Arduino UNO la fórmula sería:
Esto implica que si al emplear la función analogRead() obtenemos un valor de 276, en realidad, en el pin estaría aproximadamente:
Por ende, el voltaje real en el pin sería de alrededor de 1.35 voltios. Este conocimiento resulta fundamental para comprender el estado de tus dispositivos y sensores conectados al Arduino.
Control de un servomotor con un joystick en Arduino
Ahora exploraremos cómo emplear un joystick con Arduino. La premisa básica es obtener la posición del joystick mediante las entradas analógicas del Arduino y ajustar el ángulo de un servomotor en consecuencia.
Una vez que comprendas cómo utilizar un joystick con Arduino, las posibilidades son infinitas.
Para este proyecto necesitarás:
1x Arduino UNO * 1x Módulo Joystick 1x Servomotor Cables
- Puedes utilizar cualquier placa Arduino siempre y cuando tenga al menos dos entradas analógicas.
Anatomía de un joystick analógico
Un joystick analógico consiste en una palanca conectada a dos potenciómetros. Estos potenciómetros están dispuestos para determinar la inclinación de la palanca en los ejes x e y respectivamente. Algunos joysticks también incluyen un pulsador adicional, comúnmente denominado selector.
Vincular un joystick con arduino
Para vincular correctamente un joystick con Arduino, es fundamental seguir ciertos pasos de conexión:
-
El pin VCC debe ser enlazado al voltaje de operación del microcontrolador. Por ejemplo, en Arduino UNO se conecta al pin de 5V, mientras que en un Arduino Zero o un NodeMCU se enlaza al pin de 3.3 voltios.
-
Los pines VRx y VRy necesitan ser conectados a entradas analógicas individuales. Respectivamente, cada uno de ellos representa la posición de la palanca en los ejes x e y.
-
En cuanto al pin SW, debe ser conectado a un pin digital del Arduino.
Este esquema eléctrico muestra la disposición de los componentes para un joystick con Arduino UNO.
En el caso de placas basadas en ESP8266, como el ESP8266, solo es posible conectar un pin analógico, ya que este microcontrolador dispone únicamente de una entrada analógica (A0).
El servomotor
Para conectar el servomotor, es crucial comprender que se trata de un motor eléctrico capaz de mantener el ángulo que se le indica, lo que se logra mediante una señal PWM.
Si necesitas aclarar dudas sobre su funcionamiento, te recomiendo revisar nuestro tutorial detallado sobre cómo utilizar servomotores con Arduino en el blog.
Por lo general, un servo cuenta con tres cables: uno para la alimentación de 5 voltios, otro para la conexión a tierra y el tercero para el control a través de un pin PWM.
Integrando el servomotor al joystick con Arduino, el esquema de conexión quedaría representado como se muestra en la siguiente figura.
Programación del joystick y Arduino
Aquí está el código completo y los pasos para implementar un proyecto de joystick con Arduino:
#include <Servo.h> #define PIN_VRx A0 #define PIN_VRy A1 #define PIN_SW 2 #define PIN_SERVO 6 Servo motor; int x, y; int x_ang, y_ang; void setup() { Serial.begin(9600); pinMode(PIN_SW, INPUT_PULLUP); motor.attach(PIN_SERVO); motor.write(0); } void loop() { x = analogRead(PIN_VRx); y = analogRead(PIN_VRy); x_ang = map(x, 0, 1023, 0, 180); y_ang = map(y, 0, 1023, 0, 180); Serial.print("X_ang:"); Serial.print(x_ang); Serial.print(" Y_ang:"); Serial.print(y_ang); Serial.print(" SW:"); Serial.print(digitalRead(PIN_SW)); Serial.println(); motor.write(x_ang); delay(250); }
Este código controla un servomotor a partir de las lecturas de un joystick. La librería Servo es necesaria para manejar el servomotor. Comienza por incluir la librería y luego define las constantes para los pines del joystick y el servo.
Luego, en la función setup()
, inicializa la comunicación serial y configura el pin del pulsador como entrada con resistencia de pullup. También inicializa el servo en la posición de 0 grados.
En la función loop()
, se leen las posiciones del joystick en los ejes x e y. Estos valores se mapean a ángulos que luego se envían al servo para controlar su posición. Además, se imprime información sobre los ángulos y el estado del pulsador en el monitor serial.
Con este proyecto, puedes controlar la posición de un servo utilizando un joystick con Arduino. ¡Experimenta y diviértete!