Sensor optico + Encoder Wheel
Si en el anterior tutorial aprendimos a programar motores de corriente continua con el driver L298N y en otra lección anterior aprendimos a controlar motores paso a paso para realizar un control de posición con la librería AccelStepper, ahora vamos a realizar el control de posición y velocidad del que carecen los motores de corriente continua.
Para ello, vamos a utilizar un sensor óptico H22A1 o ITR9608 u optek opb
El sensor óptico utilizado se puede encontrar facilmente en las impresoras, en el ratón del ordenador o en otras máquinas con tambores rotativos y que sirven para aportar precisión en el giro de los mismos.
El sensor óptico se utiliza para hacer el control de encoder . Es decir, mediante una rueda ranurada podemos determinar el ángulo y la velocidad de giro contando a través de este sensor cuantas ranuras se han desplazado.
Este optointerruptor suele constar de cuatro patillas que conectan a un diodo infrarrojo y un transistor óptico. Encapsulados como se ve en la figura, el sensor se enciende y proyecta la señal a través de la rendija que excita el transistor y éste conduce la electricidad. En medio de estos dos elementos se dispone la rueda ranurada que deja o no deja pasar la luz del diodo y a medida que se producen estos cortes de luz se van contando la señal de giro.
Conexión de sensor óptico con Arduino
Sensor óptico de 4 patillas
Para este modelo de conexión es necesario montar un circuito como el siguiente.
Representamos este circuito como si de un LED que luce a una fotoresistencia. Cuando la luz llega del LED al transistor, este conduce, por lo que leeremos un valor alto en la placa. Al igual que ocurre en la fotoresistencia, que la resistencia será baja, por lo que dejará circular la corriente y el valor leido será alto. En el caso de bloquear la luz entre uno y otro, la resistencia se hace más grande y el valor leido es más cercano a cero, ya que no pasa corriente por el cable. Lo mismo ocurre con el transistor óptico, la única diferencia es que el transistor conduce o no y es un valor digital el que nos proporciona.
Sensor óptico de 3 patillas
Como se podrá ver, si recuperamos el sensor de una impresora, el conjunto puede no proporcionarnos las 4 patillas, sino 3, que son las mínimas y necesarias para hacer el circuito. Dos de los pines van conectados al común de tierra, y las otras dos, son las que están conectadas al diodo y al transistor óptico por separado. CUIDADO: Pueden aparecer otro tipo de sensores ópticos cuyo transistor tiene 3 patillas en lugar de 2. En este caso no nos servirá para nuestro robot.
Este formato nos ahorrará mucho trabajo, ya que no harán falta añadir resistencias ni cables, ya que suelen venir con el sistema de conexiones integrado.
La patilla de en medio es la señal del transistor óptico y a las otras dos irán conectadas hacia el voltaje y tierra como en el circuito anterior. No es necesario añadir una resistencia en el voltaje, tal y como indica la figura.
Programación de sensores ópticos
Para programar este sensor óptico, solamente será necesario realizar una lectura del pin 4 al que está conectada la resistencia de 10K para que sea capaz de leer los estados altos y bajos que deja pasar la rueda ranurada.
1 2 3 4 5 6 7 8 9 | void setup() { Serial.begin(9600); pinMode(8, INPUT); } void loop() { Serial.println(digitalRead(8)); } |
Una vez cargado este sencillo programa, podemos acceder al Serial Plotter y observar cómo evoluciona la señal si hacemos rodar la rueda.
En la gráfica podemos observar la señal de una rueda al girar con la mano. Por una parte, si contamos los cambios de voltaje en la señal, podemos hacer un control de posición a medida que giremos nuestra rueda por ranuras.
Por otra parte, si extendemos nuestro control en la dimensión temporal, podemos ver que hay estados que se mantienen porque son más lentos, o que están más juntos, que significa que la rueda ha girado más rápido. En este apartado podremos realizar un control de velocidad.
Tipos de Encoder Wheel
Para este tipo de control, será necesario tener en cuenta el tipo de rueda para saber cuantas revoluciones están girando.
Para ello, es suficiente contar el número de ranuras y multiplicar por 2 este valor, ya que en el siguiente ejercicio, no vamos a contar los 0’s o 1’s de la rueda, sino los cambios de la señal con interrupciones.
Es por ello, que podemos deducir que para una rueda de 20 ranuras, habrá que contar 40 cambios de voltaje en la señal para dar una vuelta completa.
Control de posición
Para controlar la posición, vamos a disponer simplemente de un contador y actualizaremos esta medida del contador cuando encontremos un cambio en la señal. Podemos repasar la lección de detección de eventos discretos para realizar este pequeño programa.
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 | int rune; boolean runestate; int nrune; int turns; boolean turnstate; void setup() { Serial.begin(9600); pinMode(2, INPUT); rune = ( int )(0); runestate = (boolean)( false ); nrune = ( int )(40); turns = ( int )(0); turnstate = (boolean)( false ); } void loop() { if (digitalRead(2) != runestate){ runestate = digitalRead(2); rune = rune + 1; Serial.println(rune); turns = rune / nrune; } if (turns != turnstate){ turnstate = turns; Serial.println((String( "Turns: " ) + String(turns))); } } |
En el momento en el que la rueda encuentre 40 cambios en la señal habrá dado una vuelta. Si podemos medir las vueltas que dan las ruedas de nuestro coche, entonces podremos medir cuanto se desplaza en linea recta.
Control de velocidad
Para conocer la velocidad a la que giran nuestras ruedas, tendremos que considerar el factor tiempo. Si ya sabemos medir el ángulo de giro de nuestras ruedas [steps], lo que tendremos que hacer será dividir por el tiempo para definir una nueva unidad de velocidad. [steps/s]
El pequeño problema que tendremos en esta cuestión será considerar cómo se actualizan las lecturas temporales; tal y como vimos en la lección sobre eventos temporales. Si una lectura tarda mucho en ejecutarse, definiremos entonces que la velocidad es 0 o está parado; éste será un primer filtro. Y en el momento que la rueda detecte movimiento; realizará lecturas para definir la velocidad.
IMPORTANTE: La velocidad la mediremos como float, ya que con la división de números enteros, perderemos precisión si lo consideramos a su vez como un entero.
Interrupts
Para gestionar este encoder es necesario conocer las interrupciones. De esta manera podemos crear un contador para conocer la posición o para medir la velocidad en cada instante de tiempo sin necesidad de medir las lecturas dentro del bucle. Para ello, conectaremos nuestros sensores a los pines 2 y 3 para medir la señal en nuestro Arduino UNO.
Las interrupciones son un tipo de funciones asociadas a eventos en unos pines concretos que tienen prioridad máxima en su ejecución con respecto a las demás definidas.
Las interrupciones suelen ser funciones muy breves, ya que una interrupción que se prolonga mucho tiempo puede causar que otras interrupciones se retrasen. Estas funciones no pueden tener parámetros de entrada ni de salida.
Las funciones que más tiempo de procesamiento conllevan son los bucles y la escritura de mensaje por el puerto serie, por lo que deben evitarse en su mayoría.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | volatile int rune = 0; int nrunes=40; int oldrune = 0; void doEncoder(){ rune++; } void setup(){ Serial.begin(9600); attachInterrupt(digitalPinToInterrupt(2), doEncoder, CHANGE); } void loop(){ if (oldrune != rune ){ Serial.println(rune); oldrune == rune ; } } |
En este programa, tendremos el problema en el que nuestro motor no sabría identificar si la rueda va hacia delante o hacia atrás, pero en el momento de realizar el movimiento de los motores, como establecemos la dirección de movimiento dentro del programa, podemos definir si sumar o restar.
En cambio, si no ejecutamos el movimiento desde el programa no tendremos forma de conocer el sentido de giro y sería necesario otro sensor para ejecutar una medida en cuadratura como el encoder rotatorio.
Los ejercicios de código, proyectos y recursos que desarrollaremos durante el curso se pueden consultar a través de nuestro Github.