Como calcular la velocidad de un motor con encoder hall

Motor con encoder hall y Arduino MEGA
Ver en Github

Hay muchos tipos de codificadores, o «encoders», para medir tanto posición como velocidad. En este artículo vamos a ver como calcular la velocidad de un motor utilizando motores con encoders de efecto hall como los que podemos encontrar en amazon,  utilizando un arduino.

💡
En calidad de Afiliado de Amazon, obtengo ingresos por las compras adscritas que cumplen los requisitos aplicables

Motor del engranaje con el codificador de Hall

Ver en Amazon

¿Qué es un codificador de efecto hall?

Un codificador de efecto hall es aquel que utiliza el efecto hall para calcular un cambio en la posición angular. El eje del motor tiene unos elementos magnéticos o imanes ensamblados de forma solidaria, es decir, giran al girar el motor que son detectados por uno o más (normalmente 2) sensores de efecto hall al girar y pasar cerca de estos. En este caso estos imanes los podemos encontrar en la rueda del extremo opuesto a la salida del eje del motor.


Al pasar cerca de los sensores de efecto hall, estos nos proporcionan con una señal, que será la que utilizaremos para hacer el cálculo de la velocidad.

Cableado del motor con encoder

A la hora de cablear el motor, es importante, como siempre, que echemos un vistazo a la documentación que viene con el componente, pero en principio deberíamos tener 6 pines:

Cableado del motor con encoder y el Arduino

Pin motor

Pin Arduino

Descripción

Color diagrama

M+

5V

Terminal positiva del motor

Naranja

Hall-

GND

Terminal negativa para el sensor hall

Amarillo

S1

2

Señal encoder 1

Morado

S2

-

Señal encoder 2

-

Hall+

3.3V

Terminal positiva para el sensor hall

Rojo

M-

GND

Terminal negativa del motor

Negro

Tengamos en cuenta que, de conectar los terminales del motor al revés, el motor simplemente girará en la dirección opuesta, pero que no debemos invertir la polaridad de la alimentación del sensor hall.

Hemos escogido el pin 2 del arduino para la señal porque se trata de una entrada apta para interrupciones, las cuales utilizaremos a continuación.

Interrupciones

Queremos que el arduino se entere cada vez que le llegue una señal del encoder, independientemente de lo que pueda estar ejecutando en ese momento. Por eso añadimos la señal del encoder a un pin con interrupciones y las activamos.

Hemos elegido el pin 2, ya que es compatible con las interrupciones en el Arduino Uno y el Arduino Nano, los dos más comunes, pero puedes comprobar que pines tienes disponibles en la página de arduino.

Código

Empezamos asignando algunas variables que después veremos en acción:

int encoderReadingPin=2; //Pin lectura señal del encoder

long m1,m2; //Tiempos para el cálculo de interrupciones
long up_times[3]={0,0,0}; //tiempos interrupciones
long t_min = 0; //duración media interrupciones
int index = 0; //indice para interrupciones
Declaración de variables

Definimos la interrupción, este código se ejecutará cada vez que se reciba la señal de la interrupción, es decir, cada vez que tengamos un pulso del sensor de efecto hall.  Básicamente lo que haremos es anotar los tiempos en una lista para después promediar el tiempo entre interrupciones y de ahí extraer la velocidad angular.

//interrupcion, aqui almacenaremos el tiempo de la señal del encoder
void int0(){
  m1=micros(); //asignamos m1 al tiempo de ahora
  up_times[index]=m1-m2; //calculamos la duración con la diferencia entre el momento presente y la última interrupción
  index=(index+1)%3; //actualizamos el índice de la lista de tiempos
  m2=m1; //actualizamos m2 para el siguiente ciclo
}
Definición de la función de interrupción

Pasamos al setup. Necesitamos asignar el pin 2 como una interrupción e inicializamos el puerto serie para leer los resultados:

void setup() {
  pinMode(encoderReadingPin, INPUT);
  digitalWrite(encoderReadingPin, HIGH); //turn on pullup resistors
  attachInterrupt(digitalPinToInterrupt(encoderReadingPin),int0,RISING);
  Serial.begin(115200);
  while(!Serial){
    ; //wait for serial port to connect
  }
}
Setup

En el loop, nos limitamos a promediar el tiempo entre interrupciones y a calcular la frecuencia del motor en función a esta información.

void loop() {
  t_min=up_times[0]+up_times[1]+up_times[2]; // tiempo medio entre interrupciones
  double motor_f=3E6/(t_min*7); //calculamos la frecuencia
  Serial.println(motor_f);
}
Loop

Es importante anotar que la fórmula aqui mostrada debe ser modificada según la cantidad de pulsos por vuelta que tenga tu motor. En nuestro caso, teníamos 7 pulsos por vuelta, por lo que:

\[ \frac{t_{min}}{3} \frac{7 pulsos}{1 vuelta} \frac{10^6 \mu s}{1 s} = \frac{7}{3} t_{min} 10^6 s^{-1} = \frac{7}{3} t_{min} 10^6 Hz \]

De tener un número diferente de pulsos por vuelta, deberíamos cambiar este 7 por el número indicado. Esta información debería estar incluida en la documentación del componente, pero en caso de no estarlo, se puede averiguar facilmente haciendo girar el eje manualmente y observando los cambios de estado de la señal del codificador con el arduino.

Así pues, todo junto, tendríamos el siguiente programa:

Ver en Github
int encoderReadingPin=2; //Pin lectura señal del encoder

long m1,m2; //Tiempos para el cálculo de interrupciones
long up_times[3]={0,0,0}; //tiempos interrupciones
long t_min = 0; //duración media interrupciones
int index = 0; //indice para interrupciones

//interrupcion, aqui almacenaremos el tiempo de la señal del encoder
void int0(){
  m1=micros(); //asignamos m1 al tiempo de ahora
  up_times[index]=m1-m2; //calculamos la duración con la diferencia entre el momento presente y la última interrupción
  index=(index+1)%3; //actualizamos el índice de la lista de tiempos
  m2=m1; //actualizamos m2 para el siguiente ciclo
}

void setup() {
  pinMode(encoderReadingPin, INPUT);
  digitalWrite(encoderReadingPin, HIGH); //turn on pullup resistors
  attachInterrupt(digitalPinToInterrupt(encoderReadingPin),int0,RISING);
  Serial.begin(115200);
  while(!Serial){
    ; //wait for serial port to connect
  }
}

void loop() {
  t_min=up_times[0]+up_times[1]+up_times[2]; // tiempo medio entre interrupciones
  double motor_f=3E6/(t_min*7); //calculamos la frecuencia
  Serial.println(motor_f);
}
Código completo, cálculo frecuencia motor encoder hall con Arduino