En el mundo de la robótica, el encoder es dispositivo esencial que nos permite medir la posición y el movimiento de los ejes de un robot de manera precisa. Estos dispositivos proporcionan información en tiempo real sobre la ubicación de los componentes mecánicos, lo que nos permite controlar y programar los movimientos de nuestros robots de manera eficiente. En este artículo, exploraremos cómo utilizar encoders de cuadratura en la robótica utilizando la plataforma Arduino, y cómo pueden mejorar el rendimiento de nuestros proyectos robóticos.
¿Qué es un encoder?
Un encoder es un dispositivo que convierte el movimiento rotativo o lineal en una señal eléctrica que se puede utilizar para medir y controlar la posición. En el contexto de la robótica, los encoders se utilizan para medir la posición de los ejes de los motores y otros componentes móviles. Estos encoders generan señales de salida en forma de pulsos eléctricos proporcionales al movimiento, que luego pueden ser interpretados por un microcontrolador como Arduino, ESP32 , etc.
Tipos de encoders utilizados en robótica
Existen diferentes tipos de encoders utilizados en robótica, pero los dos más comunes son los encoders absolutos y los encoders incrementales.
Encoders absolutos: Los encoders absolutos proporcionan una salida de señal única para cada posición del eje. Esto significa que cuando encendemos nuestro sistema, el encoder absoluto nos dará una lectura precisa de la posición inicial sin la necesidad de un punto de referencia adicional. Estos encoders son ideales para aplicaciones que requieren un control preciso de la posición, como en brazos robóticos utilizados en ensamblaje industrial.
Encoders incrementales: Los encoders incrementales generan una serie de pulsos eléctricos a medida que el eje o componente se mueve. La posición se determina contando estos pulsos. A diferencia de los encoders absolutos, los encoders incrementales no tienen información sobre la posición inicial, por lo que se requiere un punto de referencia conocido para determinar la posición absoluta. Sin embargo, son más comunes en aplicaciones donde la velocidad y la dirección del movimiento son más importantes que la posición absoluta, como en robots móviles.
Encoder de cuadratura
Estos encoders utilizan dos canales de salida, A y B, para generar señales que indican tanto el movimiento como la dirección. Estos canales producen una secuencia de pulsos en cuadratura, lo que significa que las transiciones de estado de las señales están desfasadas en 90 grados entre sí. Esta característica permite detectar la dirección del movimiento y proporciona una mayor precisión en la medición de la posición.
Dirección de movimiento
Para la determinar el sentido de giro (signo), se toman como referencia el desfasamiento que existe entre las señales AB. El hecho de trabajar con dos canales, nos lleva a tener 4 estados, estos mismos son la combinación de A y B.
Si asumimos la salida A como el bit más significativo y la salida B como el bit menos significativo, en la tabla de verdad podemos saber la dirección de giro, si comparamos el estado actual con el estado anterior. Además, en la figura también se muestra una matriz de incrementos donde podemos comparar el estado anterior con el actual y saber cómo fue el movimiento. Por ejemplo, si el estado anterior fue 01 y el estado actual del encoder es 11 podemos saber que el motor está girando en sentido anti-horario (+). Esta matriz es muy útil para saber en pocos pasos que ocurre con el encoder.
También nos puede servir para detectar errores de nuestra señal o del encoder. Ya que hay 4 combinaciones que no pueden aparecer en nuestra señal, como por ejemplo la combinación (11,00), marcada con una E en la matriz.
Aprende robótica ahora
En la robótica, cada error es una oportunidad para aprender y mejorar
30
%
Off
Resolución
La resolución de un encoder es una medida en pulsos por revolución (PPR), es decir el número de conteo (cuentas) que genera el encoder en cada vuelta. En el caso de los motores Chihai Motor CHR-GM25-370 de 140RPM a 12v, el encoder incremental de cuadratura emite 11 cuentas por revolución del eje del motor, que corresponde a 495 cuentas por revolución del eje de salida de la caja de reductora (Holzer resolution).
Precisión
Respecto a la precisión, tenemos más de una opción.
- Precisión simple, registrando un único flanco (subida o bajada) en un único canal.
- Precisión doble, registrando ambos flancos en un único canal.
- Precisión cuádruple, registrando ambos flancos en ambos canales
Resolución para una precisión cuádruple
Para aplicaciones de robótica se utiliza la precisión cuádruple, esta precisión es la que permite detectar el sentido de giro del eje del motor. Por lo tanto, la resolución del encoder para una precisión cuádruple (R) se calcula de manera diferente al Holzer resolution.
Donde:
R: Es la resolución del encoder para una precisión cuádruple.
mH: Es el número de cuentas por revolución del eje del motor (Motor Holzer). En nuestro caso 11.
s: Es el número de estados generado por los canales AB. En nuestro caso 4.
r: Es la relación de reducción de la caja reductora (ratio). En nuestro caso 45 cuentas por revolución.
Por lo tanto,
Cómo utilizar un encoder de cuadratura con Arduino
En base a la tabla anterior se debe crear un código que permita comparar el estado anterior y el estado actual de los pines C1 (canal A) y C2 (canal B) del encoder. En primer lugar, se debe detectar los flancos de subida y bajada de ambos canales AB. Para esta tarea lo más recomendable es usar interrupciones. Entonces, definimos los pines y las variables que se van a utilizar, configuramos los pines como entradas y activamos las interrupciones para detectar ambos flancos.
const int C1 = 3; // Entrada de la señal A del encoder. const int C2 = 2; // Entrada de la señal B del encoder. volatile int n = 0; volatile byte ant = 0; volatile byte act = 0; void setup() { pinMode(C1, INPUT); pinMode(C2, INPUT); attachInterrupt(digitalPinToInterrupt(C1), encoder, CHANGE); attachInterrupt(digitalPinToInterrupt(C2), encoder, CHANGE); }
En la función encoder vamos a comparar el estado anterior y actual e incrementar o decrementar un contador según la tabla.
// Encoder precisión cuádruple. void encoder(void) { ant=act; if(digitalRead(C1)) bitSet(act,1); else bitClear(act,1); if(digitalRead(C2)) bitSet(act,0); else bitClear(act,0); if(ant == 2 && act ==0) n++; if(ant == 0 && act ==1) n++; if(ant == 3 && act ==2) n++; if(ant == 1 && act ==3) n++; if(ant == 1 && act ==0) n--; if(ant == 3 && act ==1) n--; if(ant == 0 && act ==2) n--; if(ant == 2 && act ==3) n--; }
Finalmente, si cargamos el siguiente sketch en Arduino al dar una vuelta completa al eje del motor se debe mostrar en el monitor serial el valor de la resolución del encoder para una precisión cuádruple R. Para este caso R=1980.
const int C1 = 3; // Entrada de la señal A del encoder. const int C2 = 2; // Entrada de la señal B del encoder. volatile int n = 0; volatile byte ant = 0; volatile byte act = 0; unsigned long lastTime = 0; // Tiempo anterior unsigned long sampleTime = 100; // Tiempo de muestreo void setup() { Serial.begin(9600); pinMode(C1, INPUT); pinMode(C2, INPUT); attachInterrupt(digitalPinToInterrupt(C1), encoder, CHANGE); attachInterrupt(digitalPinToInterrupt(C2), encoder, CHANGE); Serial.println("Numero de conteos"); } void loop() { if (millis() - lastTime >= sampleTime || lastTime==0) { // Se actualiza cada sampleTime (milisegundos) lastTime = millis(); Serial.print("Numero de cuentas: ");Serial.println(n); } } // Encoder precisión cuádruple. void encoder(void) { ant=act; if(digitalRead(C1)) bitSet(act,1); else bitClear(act,1); if(digitalRead(C2)) bitSet(act,0); else bitClear(act,0); if(ant == 2 && act ==0) n++; if(ant == 0 && act ==1) n++; if(ant == 3 && act ==2) n++; if(ant == 1 && act ==3) n++; if(ant == 1 && act ==0) n--; if(ant == 3 && act ==1) n--; if(ant == 0 && act ==2) n--; if(ant == 2 && act ==3) n--; }
Implementa este sensor en un robot físico
Arduino| Odometría | Visión por computador | Ingeniería de control
30
%
Off
Posición en grados
Para medir la posición relativa del eje del motor, vamos a utilizar la siguiente fórmula.
Donde:
P: Es la posición relativa en grados.
n: Es el número de cuentas generadas.
R: Es la resolución del encoder para una precisión cuádruple. En nuestro caso 1980 cuentas por revolución.
Posición en grados en Arduino
const int C1 = 3; // Entrada de la señal A del encoder. const int C2 = 2; // Entrada de la señal B del encoder. volatile int n = 0; volatile byte ant = 0; volatile byte act = 0; unsigned long lastTime = 0; // Tiempo anterior unsigned long sampleTime = 100; // Tiempo de muestreo double P = 0; double R = 1980; void setup() { Serial.begin(9600); pinMode(C1, INPUT); pinMode(C2, INPUT); attachInterrupt(digitalPinToInterrupt(C1), encoder, CHANGE); attachInterrupt(digitalPinToInterrupt(C2), encoder, CHANGE); Serial.println("Numero de conteos"); } void loop() { if (millis() - lastTime >= sampleTime || lastTime==0) { // Se actualiza cada sampleTime (milisegundos) lastTime = millis(); P = (n*360.0)/R; Serial.print("Posicion en grados: ");Serial.println(P); } } // Encoder precisión cuádruple. void encoder(void) { ant=act; if(digitalRead(C1)) bitSet(act,1); else bitClear(act,1); if(digitalRead(C2)) bitSet(act,0); else bitClear(act,0); if(ant == 2 && act ==0) n++; if(ant == 0 && act ==1) n++; if(ant == 3 && act ==2) n++; if(ant == 1 && act ==3) n++; if(ant == 1 && act ==0) n--; if(ant == 3 && act ==1) n--; if(ant == 0 && act ==2) n--; if(ant == 2 && act ==3) n--; }