22 septiembre 2013

Utilizando el driver de motor DC L9110 en Arduino

¡Hola a todos otra vez!

No, ni estaba muerto ni andaba de parranda. He pasado trabajando muchísimo el último mes en un proyecto personal que está consumiendo mucho de mi tiempo. Lo bueno es que estoy aprendiendo muchísimas cosas nuevas y conociendo un montón de gente excepcional.

Por ahora los dejaré en el misterio sobre mis otros proyectos, pero quiero aprovechar esta entrada para compartirles un pequeño código en arduino para controlar el driver de motores DC L9110.

Habiendo dicho esto... ¡Comencemos!


El L9110


En entradas anteriores, hemos revisado la teoría básica sobre el funcionamiento de un Puente-H, para el alivio de muchos existen algunos circuitos integrados que realizan esta función de una manera sencilla y sin necesidad de tener que quebrarnos la cabeza con un montón de transistores y sus respectivos cálculos.

Primero, vamos a revisar la hoja técnica del L9110 para revisar la configuración de los pines y la lógica que necesitamos implementar para hacerlo funcionar.


Los pines I son los que reciben las señales de dirección del Arduino y los pines O son a donde conectaremos el motor DC para que pueda girar.

IAIBOAOB
1010
0101
0000
1100

Como pueden observar, la tabla es sumamente sencilla, las salidas reflejan las entradas de tal manera que en la práctica al tener conectado un motor en OA y OB este girará en una dirección o en la contraria dependiendo de la entrada.

Conectando el L9110


Si quieren probar el circuito antes de conectarlo a su Arduino pueden  armar el siguiente circuito de prueba:

 

Las entradas del L9110 están configuradas como "pull-up" provocando que ambas líneas se mantengan en 5V a la entrada del integrado ocasionando que el motor se detenga, al presionar un pulsador o el otro provocaremos que la dirección de giro del motor cambie.

El código para Arduino


Un nuevo truco... Los archivos de encabezados


Una vez hemos verificado que todo funciona de manera correcta, no queda más que ponernos a codificar.

Primero debemos de crear una nueva pestaña en Arduino y llamarla "name.h".


Los archivos ".h" son conocidos en el lenguaje C como "encabezados", en ellos podemos definir código que nos interesa re-utilizar entre diferentes archivos de código fuente.

Usualmente colocamos en los archivos ".h" definiciones que utilizaremos luego en nuestro código para facilitar su lectura o para abreviar la escritura de código que pueda resultar repetitivo.

Dentro de la pestaña "name.h" agregamos el siguiente código:
enum comandos {
  DETENER,
  ADELANTE,
  REVERSA
};

¿Para qué? La palabra "enum" permite crear "enumeradores", los enumeradores son estructuras de datos en C que nos permiten asociar números a palabras clave sin necesidad de tener que llevar el registro de los números que hemos asignado. Luego más adelante utilizaremos este enumerador para simplificar de sobre-manera nuestro código controlador de motor.

Este enumerador almacenará algunas palabras claves que nos permitirán definir la dirección de giro del motor DC.

Simplificando el código... Utilizando #define y arreglos


#define es una palabra clave que nos permite, de manera similar a los enums, hacer el código más legible. En nuestro caso utilizaremos un #define para establecer el número de motores que soportará nuestro Arduino.

Pero antes... vamos a asegurarnos de incluir el archivo "name.h" que acabamos de crear con #include de la siguiente manera:

#include "name.h"
// Modificar aquí para agregar más motores
#define MOTORES 2

Noten que agrego un pequeño comentario indicando que si agregan más motores, es necesario modificar el 2 en este caso, por el número de motores que estemos controlando.

El siguiente paso es definir un arreglo que guardará las líneas a donde estarán conectados nuestros controladores L9110, la idea es que guardemos las líneas en el arreglo para no estarlas escribiendo a mano luego. Esto lo hacemos de la siguiente manera:

int lineasMotor[MOTORES][2] = {
  {3, 4}, // Driver motor 0
  {5, 6}  // Driver motor 1 
  // Si hay mas motores agregarlos aqui con sus
  // respectivas líneas luego de modificar "MOTORES"
  // en la parte inferior
};

Aquí pueden observar como utilizamos la palabra "MOTORES" en el primera dimesión del arreglo, esto le indica al compilador que utilizaremos un arreglo que contendrá la cantidad de líneas que definamos al inicio.

Es muy importante notar que utilizamos un 2 en la segunda dimensión del arreglo, esto significa que por cada motor que querramos controlar, debemos definir dos arreglos internos que contengan las dos líneas conectadas a cada uno de los L9110 que deseamos controlar.

Si quisiéramos agregar más líneas simplemente agregamos el arreglo correspondiente en una nueva línea.

El siguiente paso es inicializar las líneas como salida. El siguiente código se encarga de configurar las salidas definidas en el arreglo como OUTPUT. Noten como seguimos utilizando "MOTORES" para facilitar la lectura del código:
void setup() {
  // Configura todas las líneas de motor
  // definidas en líneasMotor como Salidas
  for(int i = 0; i < MOTORES; i++) {
    pinMode(lineasMotor[i][0],OUTPUT);
    pinMode(lineasMotor[i][1],OUTPUT);
  }
}

Por último la parte más importante es la que nos permite simplificar enormemente la lectura del código. Aquí es donde se hace muy importante el uso del enumerador que definimos al principio.
// Esta función simplifica el código de controles de motores
// DC haciendo más fácil su lectura, toma como parámetro
// el número de motor y un "comando" que está definidio
// en el archivo encabezado llamado "name.h". Se utilizan
// comandos sencillos para facilitar la lectura del código
void controlarMotor(int numMotor, comandos accion) {
   switch(accion) {
     case DETENER:
       digitalWrite(lineasMotor[numMotor][0],0);
       digitalWrite(lineasMotor[numMotor][1],0);
       break;
     case ADELANTE:
       digitalWrite(lineasMotor[numMotor][0],1);
       digitalWrite(lineasMotor[numMotor][1],0);
       break;
     case REVERSA:
       digitalWrite(lineasMotor[numMotor][0],0);
       digitalWrite(lineasMotor[numMotor][1],1);
       break;
   }
}

La función anterior permite simplificar considerablemente el código de control. Esta recibe dos parámetros, primero el número de motor (comenzando desde 0) y luego la acción que requerimos por medio del enumerador. 

Esta función se encarga de utilizar el número de motor para establecer las líneas en la configuración que nos interese, de esta manera el código de control final queda de la siguiente manera:
void loop() {
  // EJEMPLOS DE CONTROL motor 0 en líneas 3 y 4
  controlarMotor(0,ADELANTE);
  delay(1000);
  controlarMotor(0,REVERSA);
  delay(1000);
  controlarMotor(0,DETENER);
  delay(1000);
  
  // EJEMPLOS DE CONTROL motor 1 en líneas 5 y 6
  controlarMotor(1,ADELANTE);
  delay(1000);
  controlarMotor(1,REVERSA);
  delay(1000);
  controlarMotor(1,DETENER);
  delay(1000);
}

Como puedes ver, el código es sumamente sencillo de leer al escribirse de esta manera. Una de las cosas importantes al programar es obtener código que pueda ser entendido sin necesidad de revisar archivos de encabezados o documentación extra. Para este ejemplo la funcion "controlarMotor(1,ADELANTE)" se puede leer como "Controlar Motor 1 Adelante" y cualquier persona, aunque no tenga ni idea de programación o electrónica, entendería cual es su función.

Ahora solo te queda conectar tus L9110 a las líneas 3, 4 y 5, 6, subir tu sketch a tu Arduino y podrás controlar fácilmente tus motores DC.

Por ahora los dejo con esta sencilla entrada y espero ponerme al día con las entradas del blog dentro de muy pronto.

No habiendo nada más que decir por ahora... ¡Hasta pronto!

+Información y recursos


2 comentarios:

Ing. Carlos Vilanova dijo...

ok man, muchas gracias por compartir... te aviso cualquier cosa... gracias una vez más... ;)

Arnoldo Montoya dijo...

Hola compañero,

Podrías compartirnos como es que se utiliza esta misma placa pero para controlar un motor a pasos? Saludos!